ruby-saml 0.8.16 → 0.9

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.

Files changed (90) hide show
  1. checksums.yaml +5 -5
  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 -89
  11. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +87 -0
  12. data/lib/onelogin/ruby-saml/logoutrequest.rb +34 -93
  13. data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -24
  14. data/lib/onelogin/ruby-saml/metadata.rb +46 -16
  15. data/lib/onelogin/ruby-saml/response.rb +62 -322
  16. data/lib/onelogin/ruby-saml/saml_message.rb +78 -0
  17. data/lib/onelogin/ruby-saml/settings.rb +54 -121
  18. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +26 -61
  19. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -84
  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 -144
  39. data/test/logoutresponse_test.rb +43 -25
  40. data/test/metadata_test.rb +87 -0
  41. data/test/request_test.rb +103 -90
  42. data/test/response_test.rb +181 -471
  43. data/test/responses/idp_descriptor.xml +3 -0
  44. data/test/responses/logoutresponse_fixtures.rb +5 -5
  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 +41 -44
  50. data/test/slo_logoutresponse_test.rb +87 -167
  51. data/test/test_helper.rb +27 -102
  52. data/test/xml_security_test.rb +114 -337
  53. metadata +34 -84
  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
@@ -0,0 +1,78 @@
1
+ require 'cgi'
2
+ require 'zlib'
3
+ require 'base64'
4
+ require "rexml/document"
5
+ require "rexml/xpath"
6
+
7
+ module OneLogin
8
+ module RubySaml
9
+ class SamlMessage
10
+ include REXML
11
+
12
+ ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
13
+ PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
14
+
15
+ def valid_saml?(document, soft = true)
16
+ Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
17
+ @schema = Nokogiri::XML::Schema(IO.read('saml-schema-protocol-2.0.xsd'))
18
+ @xml = Nokogiri::XML(document.to_s)
19
+ end
20
+ if soft
21
+ @schema.validate(@xml).map{ return false }
22
+ else
23
+ @schema.validate(@xml).map{ |error| validation_error("#{error.message}\n\n#{@xml.to_s}") }
24
+ end
25
+ end
26
+
27
+ def validation_error(message)
28
+ raise ValidationError.new(message)
29
+ end
30
+
31
+ private
32
+
33
+ def decode_raw_saml(saml)
34
+ if saml =~ /^</
35
+ return saml
36
+ elsif (decoded = decode(saml)) =~ /^</
37
+ return decoded
38
+ elsif (inflated = inflate(decoded)) =~ /^</
39
+ return inflated
40
+ end
41
+
42
+ return nil
43
+ end
44
+
45
+ def encode_raw_saml(saml, settings)
46
+ saml = Zlib::Deflate.deflate(saml, 9)[2..-5] if settings.compress_request
47
+ base64_saml = Base64.encode64(saml)
48
+ return CGI.escape(base64_saml)
49
+ end
50
+
51
+ def decode(encoded)
52
+ Base64.decode64(encoded)
53
+ end
54
+
55
+ def encode(encoded)
56
+ Base64.encode64(encoded).gsub(/\n/, "")
57
+ end
58
+
59
+ def escape(unescaped)
60
+ CGI.escape(unescaped)
61
+ end
62
+
63
+ def unescape(escaped)
64
+ CGI.unescape(escaped)
65
+ end
66
+
67
+ def inflate(deflated)
68
+ zlib = Zlib::Inflate.new(-Zlib::MAX_WBITS)
69
+ zlib.inflate(deflated)
70
+ end
71
+
72
+ def deflate(inflated)
73
+ Zlib::Deflate.deflate(inflated, 9)[2..-5]
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -1,81 +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
24
  attr_accessor :name_identifier_format
37
25
  attr_accessor :name_identifier_value
38
- attr_accessor :name_identifier_value_requested
39
26
  attr_accessor :sessionindex
40
27
  attr_accessor :compress_request
41
28
  attr_accessor :compress_response
42
29
  attr_accessor :double_quote_xml_attribute_values
43
- attr_accessor :force_authn
44
30
  attr_accessor :passive
45
31
  attr_accessor :protocol_binding
32
+ attr_accessor :attributes_index
33
+ attr_accessor :force_authn
34
+ attr_accessor :security
46
35
  attr_accessor :certificate
47
36
  attr_accessor :private_key
48
- # Work-flow
49
- 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
50
41
  # Compability
51
- attr_accessor :issuer
52
42
  attr_accessor :assertion_consumer_logout_service_url
53
43
  attr_accessor :assertion_consumer_logout_service_binding
54
44
 
55
- # @return [String] SP Entity ID
56
- #
57
- def sp_entity_id
58
- val = nil
59
- if @sp_entity_id.nil?
60
- if @issuer
61
- val = @issuer
62
- end
63
- else
64
- val = @sp_entity_id
65
- end
66
- val
67
- end
68
-
69
- # Setter for SP Entity ID.
70
- # @param val [String].
71
- #
72
- def sp_entity_id=(val)
73
- @sp_entity_id = val
74
- end
75
-
76
- # @return [String] Single Logout Service URL.
77
- #
78
- def single_logout_service_url
45
+ def single_logout_service_url()
79
46
  val = nil
80
47
  if @single_logout_service_url.nil?
81
48
  if @assertion_consumer_logout_service_url
@@ -87,16 +54,12 @@ module OneLogin
87
54
  val
88
55
  end
89
56
 
90
- # Setter for the Single Logout Service URL.
91
- # @param url [String].
92
- #
93
- def single_logout_service_url=(url)
94
- @single_logout_service_url = url
57
+ # setter
58
+ def single_logout_service_url=(val)
59
+ @single_logout_service_url = val
95
60
  end
96
61
 
97
- # @return [String] Single Logout Service Binding.
98
- #
99
- def single_logout_service_binding
62
+ def single_logout_service_binding()
100
63
  val = nil
101
64
  if @single_logout_service_binding.nil?
102
65
  if @assertion_consumer_logout_service_binding
@@ -108,76 +71,46 @@ module OneLogin
108
71
  val
109
72
  end
110
73
 
111
- # Setter for Single Logout Service Binding.
112
- #
113
- # (Currently we only support "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")
114
- # @param url [String]
115
- #
116
- def single_logout_service_binding=(url)
117
- @single_logout_service_binding = url
118
- end
119
-
120
- # Calculates the fingerprint of the IdP x509 certificate.
121
- # @return [String] The fingerprint
122
- #
123
- def get_fingerprint
124
- idp_cert_fingerprint || begin
125
- idp_cert = get_idp_cert
126
- if idp_cert
127
- Digest::SHA1.hexdigest(idp_cert.to_der).upcase.scan(/../).join(":")
128
- end
129
- end
74
+ # setter
75
+ def single_logout_service_binding=(val)
76
+ @single_logout_service_binding = val
130
77
  end
131
78
 
132
- # @return [OpenSSL::X509::Certificate|nil] Build the IdP certificate from the settings (previously format it)
133
- #
134
- def get_idp_cert
135
- return nil if idp_cert.nil?
136
-
137
- if idp_cert.respond_to?(:to_pem)
138
- idp_cert
139
- else
140
- return nil if idp_cert.empty?
141
- formatted_cert = OneLogin::RubySaml::Utils.format_cert(idp_cert)
142
- OpenSSL::X509::Certificate.new(formatted_cert)
143
- end
144
- end
145
-
146
- # @return [OpenSSL::X509::Certificate|nil] Build the SP certificate from the settings (previously format it)
147
- #
148
79
  def get_sp_cert
149
- return nil if certificate.nil? || certificate.empty?
150
-
151
- formatted_cert = OneLogin::RubySaml::Utils.format_cert(certificate)
152
- 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
153
86
  end
154
87
 
155
- # @return [OpenSSL::PKey::RSA] Build the SP private from the settings (previously format it)
156
- #
157
88
  def get_sp_key
158
- return nil if private_key.nil? || private_key.empty?
159
-
160
- formatted_private_key = OneLogin::RubySaml::Utils.format_private_key(private_key)
161
- 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
162
95
  end
163
96
 
164
97
  private
165
98
 
166
99
  DEFAULTS = {
167
- :compress_request => true,
168
- :compress_response => true,
169
- :double_quote_xml_attribute_values => false,
170
- :assertion_consumer_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST".freeze,
171
- :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,
172
104
  :security => {
173
- :authn_requests_signed => false,
174
- :logout_requests_signed => false,
175
- :logout_responses_signed => false,
176
- :embed_sign => false,
177
- :digest_method => XMLSecurity::Document::SHA1,
178
- :signature_method => XMLSecurity::Document::RSA_SHA1
179
- }.freeze
180
- }.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
+ }
181
114
  end
182
115
  end
183
116
  end
@@ -1,101 +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
15
+ @options = options
16
+ @request = decode_raw_saml(request)
17
+ @document = REXML::Document.new(@request)
18
+ end
23
19
 
24
- @options = options
25
- @request = OneLogin::RubySaml::Utils.decode_raw_saml(request)
26
- @document = XMLSecurity::SignedDocument.new(@request)
20
+ def is_valid?
21
+ validate
27
22
  end
28
23
 
29
24
  def validate!
30
25
  validate(false)
31
26
  end
32
27
 
33
- def validate(soft = true)
34
- return false unless validate_structure(soft)
35
-
36
- valid_issuer?(soft)
37
- end
38
-
28
+ # The value of the user identifier as designated by the initialization request response
39
29
  def name_id
40
30
  @name_id ||= begin
41
31
  node = REXML::XPath.first(document, "/p:LogoutRequest/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
42
- Utils.element_text(node)
32
+ node.nil? ? nil : node.text
43
33
  end
44
34
  end
45
35
 
46
- alias_method :nameid, :name_id
47
-
48
- def name_id_format
49
- @name_id_node ||= REXML::XPath.first(document, "/p:LogoutRequest/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
50
- @name_id_format ||=
51
- if @name_id_node && @name_id_node.attribute("Format")
52
- @name_id_node.attribute("Format").value
53
- end
54
- end
55
-
56
- alias_method :nameid_format, :name_id_format
57
-
58
36
  def id
59
- @id ||= begin
60
- node = REXML::XPath.first(document, "/p:LogoutRequest", { "p" => PROTOCOL } )
61
- node.nil? ? nil : node.attributes['ID']
62
- 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"]
63
42
  end
64
43
 
65
44
  def issuer
66
45
  @issuer ||= begin
67
46
  node = REXML::XPath.first(document, "/p:LogoutRequest/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
68
- Utils.element_text(node)
47
+ node.nil? ? nil : node.text
69
48
  end
70
49
  end
71
50
 
72
51
  private
73
52
 
74
- def validate_structure(soft = true)
75
- Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
76
- @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
77
- @xml = Nokogiri::XML(self.document.to_s)
78
- end
79
- if soft
80
- @schema.validate(@xml).map{ return false }
81
- else
82
- @schema.validate(@xml).map{ |error| validation_error("#{error.message}\n\n#{@xml.to_s}") }
83
- end
53
+ def validate(soft = true)
54
+ valid_saml?(document, soft) && validate_request_state(soft)
84
55
  end
85
56
 
86
- def valid_issuer?(soft = true)
87
- return true if settings.nil? || settings.idp_entity_id.nil? || issuer.nil?
88
-
89
- unless OneLogin::RubySaml::Utils.uri_match?(issuer, settings.idp_entity_id)
90
- 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")
91
60
  end
92
61
  true
93
62
  end
94
63
 
95
- def validation_error(message)
96
- raise ValidationError.new(message)
97
- end
98
-
99
64
  end
100
65
  end
101
66
  end
@@ -1,33 +1,17 @@
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_reader :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
- # Creates the Logout Response string.
25
- # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
26
- # @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
27
- # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
28
- # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
29
- # @return [String] Logout Request string that includes the SAMLRequest
30
- #
31
15
  def create(settings, request_id = nil, logout_message = nil, params = {})
32
16
  params = create_params(settings, request_id, logout_message, params)
33
17
  params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
@@ -36,27 +20,12 @@ module OneLogin
36
20
  params.each_pair do |key, value|
37
21
  response_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
38
22
  end
39
- 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
+
40
24
  @logout_url = settings.idp_slo_target_url + response_params
41
25
  end
42
26
 
43
- # Creates the Get parameters for the logout response.
44
- # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
45
- # @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
46
- # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
47
- # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
48
- # @return [Hash] Parameters
49
- #
50
27
  def create_params(settings, request_id = nil, logout_message = nil, params = {})
51
- # The method expects :RelayState but sometimes we get 'RelayState' instead.
52
- # Based on the HashWithIndifferentAccess value in Rails we could experience
53
- # conflicts so this line will solve them.
54
- relay_state = params[:RelayState] || params['RelayState']
55
-
56
- if relay_state.nil?
57
- params.delete(:RelayState)
58
- params.delete('RelayState')
59
- end
28
+ params = {} if params.nil?
60
29
 
61
30
  response_doc = create_logout_response_xml_doc(settings, request_id, logout_message)
62
31
  response_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
@@ -66,29 +35,18 @@ module OneLogin
66
35
 
67
36
  Logging.debug "Created SLO Logout Response: #{response}"
68
37
 
69
- response = Zlib::Deflate.deflate(response, 9)[2..-5] if settings.compress_response
70
- if Base64.respond_to?('strict_encode64')
71
- base64_response = Base64.strict_encode64(response)
72
- else
73
- base64_response = Base64.encode64(response).gsub(/\n/, "")
74
- end
38
+ response = deflate(response) if settings.compress_response
39
+ base64_response = encode(response)
75
40
  response_params = {"SAMLResponse" => base64_response}
76
41
 
77
42
  if settings.security[:logout_responses_signed] && !settings.security[:embed_sign] && settings.private_key
78
- params['SigAlg'] = settings.security[:signature_method]
79
- url_string = OneLogin::RubySaml::Utils.build_query(
80
- :type => 'SAMLResponse',
81
- :data => base64_response,
82
- :relay_state => relay_state,
83
- :sig_alg => params['SigAlg']
84
- )
85
- sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
86
- signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
87
- if Base64.respond_to?('strict_encode64')
88
- params['Signature'] = Base64.strict_encode64(signature)
89
- else
90
- params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
91
- 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)
92
50
  end
93
51
 
94
52
  params.each_pair do |key, value|
@@ -98,18 +56,7 @@ module OneLogin
98
56
  response_params
99
57
  end
100
58
 
101
- # Creates the SAMLResponse String.
102
- # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
103
- # @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
104
- # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
105
- # @return [String] The SAMLResponse String.
106
- #
107
59
  def create_logout_response_xml_doc(settings, request_id = nil, logout_message = nil)
108
- document = create_xml_document(settings, request_id, logout_message)
109
- sign_document(document, settings)
110
- end
111
-
112
- def create_xml_document(settings, request_id = nil, logout_message = nil)
113
60
  time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
114
61
 
115
62
  response_doc = XMLSecurity::Document.new
@@ -120,12 +67,7 @@ module OneLogin
120
67
  root.attributes['IssueInstant'] = time
121
68
  root.attributes['Version'] = '2.0'
122
69
  root.attributes['InResponseTo'] = request_id unless request_id.nil?
123
- root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
124
-
125
- if settings.sp_entity_id != nil
126
- issuer = root.add_element "saml:Issuer"
127
- issuer.text = settings.sp_entity_id
128
- end
70
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil?
129
71
 
130
72
  # add success message
131
73
  status = root.add_element 'samlp:Status'
@@ -139,18 +81,19 @@ module OneLogin
139
81
  status_message = status.add_element 'samlp:StatusMessage'
140
82
  status_message.text = logout_message
141
83
 
142
- response_doc
143
- end
84
+ if settings.issuer != nil
85
+ issuer = root.add_element "saml:Issuer"
86
+ issuer.text = settings.issuer
87
+ end
144
88
 
145
- def sign_document(document, settings)
146
- # embed signature
89
+ # embebed sign
147
90
  if settings.security[:logout_responses_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
148
- private_key = settings.get_sp_key
149
- cert = settings.get_sp_cert
150
- 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])
151
94
  end
152
95
 
153
- document
96
+ response_doc
154
97
  end
155
98
 
156
99
  end