ruby-saml 0.8.18 → 0.9

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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -6
  4. data/Gemfile +2 -12
  5. data/README.md +363 -35
  6. data/Rakefile +14 -0
  7. data/changelog.md +22 -9
  8. data/lib/onelogin/ruby-saml/attribute_service.rb +34 -0
  9. data/lib/onelogin/ruby-saml/attributes.rb +26 -64
  10. data/lib/onelogin/ruby-saml/authrequest.rb +47 -93
  11. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +87 -0
  12. data/lib/onelogin/ruby-saml/logoutrequest.rb +36 -100
  13. data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -35
  14. data/lib/onelogin/ruby-saml/metadata.rb +46 -16
  15. data/lib/onelogin/ruby-saml/response.rb +63 -373
  16. data/lib/onelogin/ruby-saml/saml_message.rb +78 -0
  17. data/lib/onelogin/ruby-saml/settings.rb +54 -122
  18. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +25 -71
  19. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +37 -102
  20. data/lib/onelogin/ruby-saml/utils.rb +32 -199
  21. data/lib/onelogin/ruby-saml/version.rb +1 -1
  22. data/lib/ruby-saml.rb +5 -2
  23. data/lib/schemas/{saml20assertion_schema.xsd → saml-schema-assertion-2.0.xsd} +283 -283
  24. data/lib/schemas/saml-schema-authn-context-2.0.xsd +23 -0
  25. data/lib/schemas/saml-schema-authn-context-types-2.0.xsd +821 -0
  26. data/lib/schemas/saml-schema-metadata-2.0.xsd +339 -0
  27. data/lib/schemas/{saml20protocol_schema.xsd → saml-schema-protocol-2.0.xsd} +302 -302
  28. data/lib/schemas/sstc-metadata-attr.xsd +35 -0
  29. data/lib/schemas/sstc-saml-attribute-ext.xsd +25 -0
  30. data/lib/schemas/sstc-saml-metadata-algsupport-v1.0.xsd +41 -0
  31. data/lib/schemas/sstc-saml-metadata-ui-v1.0.xsd +89 -0
  32. data/lib/schemas/{xenc_schema.xsd → xenc-schema.xsd} +1 -11
  33. data/lib/schemas/xml.xsd +287 -0
  34. data/lib/schemas/{xmldsig_schema.xsd → xmldsig-core-schema.xsd} +0 -9
  35. data/lib/xml_security.rb +83 -235
  36. data/ruby-saml.gemspec +1 -0
  37. data/test/idp_metadata_parser_test.rb +54 -0
  38. data/test/logoutrequest_test.rb +68 -155
  39. data/test/logoutresponse_test.rb +43 -32
  40. data/test/metadata_test.rb +87 -0
  41. data/test/request_test.rb +102 -99
  42. data/test/response_test.rb +181 -495
  43. data/test/responses/idp_descriptor.xml +3 -0
  44. data/test/responses/logoutresponse_fixtures.rb +7 -8
  45. data/test/responses/response_no_cert_and_encrypted_attrs.xml +29 -0
  46. data/test/responses/response_with_multiple_attribute_values.xml +1 -1
  47. data/test/responses/slo_request.xml +4 -0
  48. data/test/settings_test.rb +25 -112
  49. data/test/slo_logoutrequest_test.rb +40 -50
  50. data/test/slo_logoutresponse_test.rb +86 -185
  51. data/test/test_helper.rb +27 -102
  52. data/test/xml_security_test.rb +114 -337
  53. metadata +30 -81
  54. data/lib/onelogin/ruby-saml/setting_error.rb +0 -6
  55. data/test/certificates/certificate.der +0 -0
  56. data/test/certificates/formatted_certificate +0 -14
  57. data/test/certificates/formatted_chained_certificate +0 -42
  58. data/test/certificates/formatted_private_key +0 -12
  59. data/test/certificates/formatted_rsa_private_key +0 -12
  60. data/test/certificates/invalid_certificate1 +0 -1
  61. data/test/certificates/invalid_certificate2 +0 -1
  62. data/test/certificates/invalid_certificate3 +0 -12
  63. data/test/certificates/invalid_chained_certificate1 +0 -1
  64. data/test/certificates/invalid_private_key1 +0 -1
  65. data/test/certificates/invalid_private_key2 +0 -1
  66. data/test/certificates/invalid_private_key3 +0 -10
  67. data/test/certificates/invalid_rsa_private_key1 +0 -1
  68. data/test/certificates/invalid_rsa_private_key2 +0 -1
  69. data/test/certificates/invalid_rsa_private_key3 +0 -10
  70. data/test/certificates/ruby-saml-2.crt +0 -15
  71. data/test/requests/logoutrequest_fixtures.rb +0 -47
  72. data/test/responses/encrypted_new_attack.xml.base64 +0 -1
  73. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
  74. data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
  75. data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
  76. data/test/responses/invalids/no_signature.xml.base64 +0 -1
  77. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
  78. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
  79. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
  80. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  81. data/test/responses/response_with_concealed_signed_assertion.xml +0 -51
  82. data/test/responses/response_with_doubled_signed_assertion.xml +0 -49
  83. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  84. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  85. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  86. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  87. data/test/responses/response_wrapped.xml.base64 +0 -150
  88. data/test/responses/valid_response.xml.base64 +0 -1
  89. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  90. data/test/utils_test.rb +0 -231
@@ -1,82 +1,48 @@
1
- require "xml_security"
2
- require "onelogin/ruby-saml/utils"
3
-
4
1
  module OneLogin
5
2
  module RubySaml
6
3
  class Settings
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
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
10
+ @attribute_consuming_service = AttributeService.new
23
11
  end
24
12
 
25
- #idp data
13
+ # IdP Data
14
+ attr_accessor :idp_entity_id
26
15
  attr_accessor :idp_sso_target_url
27
- attr_accessor :idp_cert_fingerprint
28
- attr_accessor :idp_cert
29
16
  attr_accessor :idp_slo_target_url
30
- attr_accessor :idp_entity_id
31
- #sp data
32
- attr_accessor :sp_entity_id
17
+ attr_accessor :idp_cert
18
+ attr_accessor :idp_cert_fingerprint
19
+ # SP Data
20
+ attr_accessor :issuer
33
21
  attr_accessor :assertion_consumer_service_url
34
- attr_accessor :authn_context
22
+ attr_accessor :assertion_consumer_service_binding
35
23
  attr_accessor :sp_name_qualifier
36
- attr_accessor :idp_name_qualifier
37
24
  attr_accessor :name_identifier_format
38
25
  attr_accessor :name_identifier_value
39
- attr_accessor :name_identifier_value_requested
40
26
  attr_accessor :sessionindex
41
27
  attr_accessor :compress_request
42
28
  attr_accessor :compress_response
43
29
  attr_accessor :double_quote_xml_attribute_values
44
- attr_accessor :force_authn
45
30
  attr_accessor :passive
46
31
  attr_accessor :protocol_binding
32
+ attr_accessor :attributes_index
33
+ attr_accessor :force_authn
34
+ attr_accessor :security
47
35
  attr_accessor :certificate
48
36
  attr_accessor :private_key
49
- # Work-flow
50
- attr_accessor :security
37
+ attr_accessor :authn_context
38
+ attr_accessor :authn_context_comparison
39
+ attr_accessor :authn_context_decl_ref
40
+ attr_reader :attribute_consuming_service
51
41
  # Compability
52
- attr_accessor :issuer
53
42
  attr_accessor :assertion_consumer_logout_service_url
54
43
  attr_accessor :assertion_consumer_logout_service_binding
55
44
 
56
- # @return [String] SP Entity ID
57
- #
58
- def sp_entity_id
59
- val = nil
60
- if @sp_entity_id.nil?
61
- if @issuer
62
- val = @issuer
63
- end
64
- else
65
- val = @sp_entity_id
66
- end
67
- val
68
- end
69
-
70
- # Setter for SP Entity ID.
71
- # @param val [String].
72
- #
73
- def sp_entity_id=(val)
74
- @sp_entity_id = val
75
- end
76
-
77
- # @return [String] Single Logout Service URL.
78
- #
79
- def single_logout_service_url
45
+ def single_logout_service_url()
80
46
  val = nil
81
47
  if @single_logout_service_url.nil?
82
48
  if @assertion_consumer_logout_service_url
@@ -88,16 +54,12 @@ module OneLogin
88
54
  val
89
55
  end
90
56
 
91
- # Setter for the Single Logout Service URL.
92
- # @param url [String].
93
- #
94
- def single_logout_service_url=(url)
95
- @single_logout_service_url = url
57
+ # setter
58
+ def single_logout_service_url=(val)
59
+ @single_logout_service_url = val
96
60
  end
97
61
 
98
- # @return [String] Single Logout Service Binding.
99
- #
100
- def single_logout_service_binding
62
+ def single_logout_service_binding()
101
63
  val = nil
102
64
  if @single_logout_service_binding.nil?
103
65
  if @assertion_consumer_logout_service_binding
@@ -109,76 +71,46 @@ module OneLogin
109
71
  val
110
72
  end
111
73
 
112
- # Setter for Single Logout Service Binding.
113
- #
114
- # (Currently we only support "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")
115
- # @param url [String]
116
- #
117
- def single_logout_service_binding=(url)
118
- @single_logout_service_binding = url
119
- end
120
-
121
- # Calculates the fingerprint of the IdP x509 certificate.
122
- # @return [String] The fingerprint
123
- #
124
- def get_fingerprint
125
- idp_cert_fingerprint || begin
126
- idp_cert = get_idp_cert
127
- if idp_cert
128
- Digest::SHA1.hexdigest(idp_cert.to_der).upcase.scan(/../).join(":")
129
- end
130
- end
74
+ # setter
75
+ def single_logout_service_binding=(val)
76
+ @single_logout_service_binding = val
131
77
  end
132
78
 
133
- # @return [OpenSSL::X509::Certificate|nil] Build the IdP certificate from the settings (previously format it)
134
- #
135
- def get_idp_cert
136
- return nil if idp_cert.nil?
137
-
138
- if idp_cert.respond_to?(:to_pem)
139
- idp_cert
140
- else
141
- return nil if idp_cert.empty?
142
- formatted_cert = OneLogin::RubySaml::Utils.format_cert(idp_cert)
143
- OpenSSL::X509::Certificate.new(formatted_cert)
144
- end
145
- end
146
-
147
- # @return [OpenSSL::X509::Certificate|nil] Build the SP certificate from the settings (previously format it)
148
- #
149
79
  def get_sp_cert
150
- return nil if certificate.nil? || certificate.empty?
151
-
152
- formatted_cert = OneLogin::RubySaml::Utils.format_cert(certificate)
153
- OpenSSL::X509::Certificate.new(formatted_cert)
80
+ cert = nil
81
+ if self.certificate
82
+ formated_cert = OneLogin::RubySaml::Utils.format_cert(self.certificate)
83
+ cert = OpenSSL::X509::Certificate.new(formated_cert)
84
+ end
85
+ cert
154
86
  end
155
87
 
156
- # @return [OpenSSL::PKey::RSA] Build the SP private from the settings (previously format it)
157
- #
158
88
  def get_sp_key
159
- return nil if private_key.nil? || private_key.empty?
160
-
161
- formatted_private_key = OneLogin::RubySaml::Utils.format_private_key(private_key)
162
- OpenSSL::PKey::RSA.new(formatted_private_key)
89
+ private_key = nil
90
+ if self.private_key
91
+ formated_private_key = OneLogin::RubySaml::Utils.format_private_key(self.private_key)
92
+ private_key = OpenSSL::PKey::RSA.new(formated_private_key)
93
+ end
94
+ private_key
163
95
  end
164
96
 
165
97
  private
166
98
 
167
99
  DEFAULTS = {
168
- :compress_request => true,
169
- :compress_response => true,
170
- :double_quote_xml_attribute_values => false,
171
- :assertion_consumer_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST".freeze,
172
- :single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze,
100
+ :assertion_consumer_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
101
+ :single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
102
+ :compress_request => true,
103
+ :compress_response => true,
173
104
  :security => {
174
- :authn_requests_signed => false,
175
- :logout_requests_signed => false,
176
- :logout_responses_signed => false,
177
- :embed_sign => false,
178
- :digest_method => XMLSecurity::Document::SHA1,
179
- :signature_method => XMLSecurity::Document::RSA_SHA1
180
- }.freeze
181
- }.freeze
105
+ :authn_requests_signed => false,
106
+ :logout_requests_signed => false,
107
+ :logout_responses_signed => false,
108
+ :embed_sign => false,
109
+ :digest_method => XMLSecurity::Document::SHA1,
110
+ :signature_method => XMLSecurity::Document::SHA1
111
+ },
112
+ :double_quote_xml_attribute_values => false,
113
+ }
182
114
  end
183
115
  end
184
116
  end
@@ -1,112 +1,66 @@
1
- require "xml_security"
2
- require "time"
1
+ require 'zlib'
2
+ require 'time'
3
+ require 'nokogiri'
3
4
 
4
5
  # Only supports SAML 2.0
5
- # SAML2 Logout Request (SLO IdP initiated, Parser)
6
6
  module OneLogin
7
7
  module RubySaml
8
- class SloLogoutrequest
9
-
10
- ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
11
- PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
12
-
13
- # OneLogin::RubySaml::Settings Toolkit settings
14
- attr_accessor :settings
15
-
16
- attr_reader :document
17
- attr_reader :request
8
+ class SloLogoutrequest < SamlMessage
18
9
  attr_reader :options
10
+ attr_reader :request
11
+ attr_reader :document
19
12
 
20
- def initialize(request, settings = nil, options = {})
13
+ def initialize(request, options = {})
21
14
  raise ArgumentError.new("Request cannot be nil") if request.nil?
22
- self.settings = settings
23
-
24
- @options = options
25
- @request = OneLogin::RubySaml::Utils.decode_raw_saml(request)
26
- @document = XMLSecurity::SignedDocument.new(@request)
15
+ @options = options
16
+ @request = decode_raw_saml(request)
17
+ @document = REXML::Document.new(@request)
27
18
  end
28
19
 
29
- def request_id
30
- @request_id ||= begin
31
- node = REXML::XPath.first(
32
- document,
33
- "/p:LogoutRequest",
34
- { "p" => PROTOCOL }
35
- )
36
- node.nil? ? nil : node.attributes['ID']
37
- end
20
+ def is_valid?
21
+ validate
38
22
  end
39
23
 
40
24
  def validate!
41
25
  validate(false)
42
26
  end
43
27
 
44
- def validate(soft = true)
45
- return false unless validate_structure(soft)
46
-
47
- valid_issuer?(soft)
48
- end
49
-
28
+ # The value of the user identifier as designated by the initialization request response
50
29
  def name_id
51
30
  @name_id ||= begin
52
31
  node = REXML::XPath.first(document, "/p:LogoutRequest/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
53
- Utils.element_text(node)
32
+ node.nil? ? nil : node.text
54
33
  end
55
34
  end
56
35
 
57
- alias_method :nameid, :name_id
58
-
59
- def name_id_format
60
- @name_id_node ||= REXML::XPath.first(document, "/p:LogoutRequest/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
61
- @name_id_format ||=
62
- if @name_id_node && @name_id_node.attribute("Format")
63
- @name_id_node.attribute("Format").value
64
- end
65
- end
66
-
67
- alias_method :nameid_format, :name_id_format
68
-
69
36
  def id
70
- @id ||= begin
71
- node = REXML::XPath.first(document, "/p:LogoutRequest", { "p" => PROTOCOL } )
72
- node.nil? ? nil : node.attributes['ID']
73
- end
37
+ return @id if @id
38
+ element = REXML::XPath.first(document, "/p:LogoutRequest", {
39
+ "p" => PROTOCOL} )
40
+ return nil if element.nil?
41
+ return element.attributes["ID"]
74
42
  end
75
43
 
76
44
  def issuer
77
45
  @issuer ||= begin
78
46
  node = REXML::XPath.first(document, "/p:LogoutRequest/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
79
- Utils.element_text(node)
47
+ node.nil? ? nil : node.text
80
48
  end
81
49
  end
82
50
 
83
51
  private
84
52
 
85
- def validate_structure(soft = true)
86
- Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
87
- @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
88
- @xml = Nokogiri::XML(self.document.to_s)
89
- end
90
- if soft
91
- @schema.validate(@xml).map{ return false }
92
- else
93
- @schema.validate(@xml).map{ |error| validation_error("#{error.message}\n\n#{@xml.to_s}") }
94
- end
53
+ def validate(soft = true)
54
+ valid_saml?(document, soft) && validate_request_state(soft)
95
55
  end
96
56
 
97
- def valid_issuer?(soft = true)
98
- return true if settings.nil? || settings.idp_entity_id.nil? || issuer.nil?
99
-
100
- unless OneLogin::RubySaml::Utils.uri_match?(issuer, settings.idp_entity_id)
101
- return soft ? false : validation_error("Doesn't match the issuer, expected: <#{self.settings.idp_entity_id}>, but was: <#{issuer}>")
57
+ def validate_request_state(soft = true)
58
+ if request.empty?
59
+ return soft ? false : validation_error("Blank request")
102
60
  end
103
61
  true
104
62
  end
105
63
 
106
- def validation_error(message)
107
- raise ValidationError.new(message)
108
- end
109
-
110
64
  end
111
65
  end
112
66
  end
@@ -1,70 +1,33 @@
1
- require "base64"
2
- require "zlib"
3
- require "cgi"
4
- require "onelogin/ruby-saml/utils"
5
- require "onelogin/ruby-saml/setting_error"
1
+ require "uuid"
2
+
3
+ require "onelogin/ruby-saml/logging"
6
4
 
7
5
  module OneLogin
8
6
  module RubySaml
7
+ class SloLogoutresponse < SamlMessage
9
8
 
10
- # SAML2 Logout Response (SLO SP initiated)
11
- #
12
- class SloLogoutresponse
13
-
14
- # Logout Response ID
15
- attr_accessor :uuid
9
+ attr_reader :uuid # Can be obtained if neccessary
16
10
 
17
- # Initializes the Logout Response. A SloLogoutresponse Object.
18
- # Asigns an ID, a random uuid.
19
- #
20
11
  def initialize
21
- @uuid = OneLogin::RubySaml::Utils.uuid
12
+ @uuid = "_" + UUID.new.generate
22
13
  end
23
14
 
24
- def response_id
25
- @uuid
26
- end
27
-
28
- # Creates the Logout Response string.
29
- # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
30
- # @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
31
- # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
32
- # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
33
- # @param logout_status_code [String] The StatusCode to be placed as StatusMessage in the logout response
34
- # @return [String] Logout Request string that includes the SAMLRequest
35
- #
36
- def create(settings, request_id = nil, logout_message = nil, params = {}, logout_status_code = nil)
37
- params = create_params(settings, request_id, logout_message, params, logout_status_code)
15
+ def create(settings, request_id = nil, logout_message = nil, params = {})
16
+ params = create_params(settings, request_id, logout_message, params)
38
17
  params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
39
18
  saml_response = CGI.escape(params.delete("SAMLResponse"))
40
19
  response_params = "#{params_prefix}SAMLResponse=#{saml_response}"
41
20
  params.each_pair do |key, value|
42
21
  response_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
43
22
  end
44
- raise SettingError.new "Invalid settings, idp_slo_target_url is not set!" if settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
23
+
45
24
  @logout_url = settings.idp_slo_target_url + response_params
46
25
  end
47
26
 
48
- # Creates the Get parameters for the logout response.
49
- # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
50
- # @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
51
- # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
52
- # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
53
- # @param logout_status_code [String] The StatusCode to be placed as StatusMessage in the logout response
54
- # @return [Hash] Parameters
55
- #
56
- def create_params(settings, request_id = nil, logout_message = nil, params = {}, logout_status_code = nil)
57
- # The method expects :RelayState but sometimes we get 'RelayState' instead.
58
- # Based on the HashWithIndifferentAccess value in Rails we could experience
59
- # conflicts so this line will solve them.
60
- relay_state = params[:RelayState] || params['RelayState']
61
-
62
- if relay_state.nil?
63
- params.delete(:RelayState)
64
- params.delete('RelayState')
65
- end
27
+ def create_params(settings, request_id = nil, logout_message = nil, params = {})
28
+ params = {} if params.nil?
66
29
 
67
- response_doc = create_logout_response_xml_doc(settings, request_id, logout_message, logout_status_code)
30
+ response_doc = create_logout_response_xml_doc(settings, request_id, logout_message)
68
31
  response_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
69
32
 
70
33
  response = ""
@@ -72,29 +35,18 @@ module OneLogin
72
35
 
73
36
  Logging.debug "Created SLO Logout Response: #{response}"
74
37
 
75
- response = Zlib::Deflate.deflate(response, 9)[2..-5] if settings.compress_response
76
- if Base64.respond_to?('strict_encode64')
77
- base64_response = Base64.strict_encode64(response)
78
- else
79
- base64_response = Base64.encode64(response).gsub(/\n/, "")
80
- end
38
+ response = deflate(response) if settings.compress_response
39
+ base64_response = encode(response)
81
40
  response_params = {"SAMLResponse" => base64_response}
82
41
 
83
42
  if settings.security[:logout_responses_signed] && !settings.security[:embed_sign] && settings.private_key
84
- params['SigAlg'] = settings.security[:signature_method]
85
- url_string = OneLogin::RubySaml::Utils.build_query(
86
- :type => 'SAMLResponse',
87
- :data => base64_response,
88
- :relay_state => relay_state,
89
- :sig_alg => params['SigAlg']
90
- )
91
- sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
92
- signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
93
- if Base64.respond_to?('strict_encode64')
94
- params['Signature'] = Base64.strict_encode64(signature)
95
- else
96
- params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
97
- end
43
+ params['SigAlg'] = XMLSecurity::Document::SHA1
44
+ url_string = "SAMLResponse=#{CGI.escape(base64_response)}"
45
+ url_string += "&RelayState=#{CGI.escape(params['RelayState'])}" if params['RelayState']
46
+ url_string += "&SigAlg=#{CGI.escape(params['SigAlg'])}"
47
+ private_key = settings.get_sp_key()
48
+ signature = private_key.sign(XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method]).new, url_string)
49
+ params['Signature'] = encode(signature)
98
50
  end
99
51
 
100
52
  params.each_pair do |key, value|
@@ -104,19 +56,7 @@ module OneLogin
104
56
  response_params
105
57
  end
106
58
 
107
- # Creates the SAMLResponse String.
108
- # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
109
- # @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
110
- # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
111
- # @param logout_status_code [String] The StatusCode to be placed as StatusMessage in the logout response
112
- # @return [String] The SAMLResponse String.
113
- #
114
- def create_logout_response_xml_doc(settings, request_id = nil, logout_message = nil, logout_status_code = nil)
115
- document = create_xml_document(settings, request_id, logout_message, logout_status_code)
116
- sign_document(document, settings)
117
- end
118
-
119
- def create_xml_document(settings, request_id = nil, logout_message = nil, status_code = nil)
59
+ def create_logout_response_xml_doc(settings, request_id = nil, logout_message = nil)
120
60
  time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
121
61
 
122
62
  response_doc = XMLSecurity::Document.new
@@ -127,38 +67,33 @@ module OneLogin
127
67
  root.attributes['IssueInstant'] = time
128
68
  root.attributes['Version'] = '2.0'
129
69
  root.attributes['InResponseTo'] = request_id unless request_id.nil?
130
- root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
70
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil?
131
71
 
132
- if settings.sp_entity_id != nil
133
- issuer = root.add_element "saml:Issuer"
134
- issuer.text = settings.sp_entity_id
135
- end
136
-
137
- # add status
72
+ # add success message
138
73
  status = root.add_element 'samlp:Status'
139
74
 
140
- # status code
141
- status_code ||= 'urn:oasis:names:tc:SAML:2.0:status:Success'
142
- status_code_elem = status.add_element 'samlp:StatusCode'
143
- status_code_elem.attributes['Value'] = status_code
75
+ # success status code
76
+ status_code = status.add_element 'samlp:StatusCode'
77
+ status_code.attributes['Value'] = 'urn:oasis:names:tc:SAML:2.0:status:Success'
144
78
 
145
- # status message
79
+ # success status message
146
80
  logout_message ||= 'Successfully Signed Out'
147
81
  status_message = status.add_element 'samlp:StatusMessage'
148
82
  status_message.text = logout_message
149
83
 
150
- response_doc
151
- end
84
+ if settings.issuer != nil
85
+ issuer = root.add_element "saml:Issuer"
86
+ issuer.text = settings.issuer
87
+ end
152
88
 
153
- def sign_document(document, settings)
154
- # embed signature
89
+ # embebed sign
155
90
  if settings.security[:logout_responses_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
156
- private_key = settings.get_sp_key
157
- cert = settings.get_sp_cert
158
- document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
91
+ private_key = settings.get_sp_key()
92
+ cert = settings.get_sp_cert()
93
+ response_doc.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
159
94
  end
160
95
 
161
- document
96
+ response_doc
162
97
  end
163
98
 
164
99
  end