ruby-saml 0.8.10 → 0.8.11

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
- SHA256:
3
- metadata.gz: 1a564ad5fdd002f4648b22638bf51dd7ad029ea633484289c7ce2e8759a3c5d6
4
- data.tar.gz: 15d0f1c459006f4c65fc9cb916b29b55098e68d9e3c5123080737b41b4e5e449
2
+ SHA1:
3
+ metadata.gz: 10ec0e5a4a9fc6a7f65613599597cef7ae8b8293
4
+ data.tar.gz: 0b63798d5d6b78e3073ccb899e355e6aa0134648
5
5
  SHA512:
6
- metadata.gz: 943d65750b9895285e60b24d612c1cce77bef3a262387121ccf9b7f8536ebfea27874d3a68ff095dc1a36e2bc3c53f509de07d2e4e31c02a20437e18015af561
7
- data.tar.gz: ccf1223639a43235641ba2533e61473e4ff248624571cd05177ccd1dd0611f7d8df16f405fd74af2987112a988f5fcb0f2f6c54fe3830f89d3688964780ea333
6
+ metadata.gz: 1883986a5fd1b3925e6745bf7d259a907c656d36958efe50dfb760192c8273a3723b76344ee542a3a07b84da677808fad850b8bd272d949c5ce7fcd8c171a881
7
+ data.tar.gz: 8538b7c75961e99186b320ff1425fb82fa0c759e3e7267eaad76659adf9f0ba98249207122092dbc383f464c1c600b03a37f010d5a3e8bfa7fbb6fba0aaa8915
@@ -2,6 +2,7 @@ require "base64"
2
2
  require "zlib"
3
3
  require "cgi"
4
4
  require "onelogin/ruby-saml/utils"
5
+ require "onelogin/ruby-saml/setting_error"
5
6
 
6
7
  module OneLogin
7
8
  module RubySaml
@@ -25,7 +26,7 @@ module OneLogin
25
26
  params.each_pair do |key, value|
26
27
  request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
27
28
  end
28
- raise "Invalid settings, idp_sso_target_url is not set!" if settings.idp_sso_target_url.nil?
29
+ raise SettingError.new "Invalid settings, idp_sso_target_url is not set!" if settings.idp_sso_target_url.nil? or settings.idp_sso_target_url.empty?
29
30
  @login_url = settings.idp_sso_target_url + request_params
30
31
  end
31
32
 
@@ -101,7 +102,7 @@ module OneLogin
101
102
  root.attributes['ID'] = uuid
102
103
  root.attributes['IssueInstant'] = time
103
104
  root.attributes['Version'] = "2.0"
104
- root.attributes['Destination'] = settings.idp_sso_target_url unless settings.idp_sso_target_url.nil?
105
+ root.attributes['Destination'] = settings.idp_sso_target_url unless settings.idp_sso_target_url.nil? or settings.idp_sso_target_url.empty?
105
106
  root.attributes['IsPassive'] = settings.passive unless settings.passive.nil?
106
107
  root.attributes['ProtocolBinding'] = settings.protocol_binding unless settings.protocol_binding.nil?
107
108
  root.attributes['ForceAuthn'] = settings.force_authn unless settings.force_authn.nil?
@@ -3,6 +3,7 @@ require "zlib"
3
3
  require "cgi"
4
4
  require 'rexml/document'
5
5
  require "onelogin/ruby-saml/utils"
6
+ require "onelogin/ruby-saml/setting_error"
6
7
 
7
8
  module OneLogin
8
9
  module RubySaml
@@ -23,6 +24,7 @@ module OneLogin
23
24
  params.each_pair do |key, value|
24
25
  request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
25
26
  end
27
+ 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?
26
28
  @logout_url = settings.idp_slo_target_url + request_params
27
29
  end
28
30
 
@@ -103,6 +105,7 @@ module OneLogin
103
105
  root.attributes['ID'] = uuid
104
106
  root.attributes['IssueInstant'] = time
105
107
  root.attributes['Version'] = "2.0"
108
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
106
109
 
107
110
  if settings.sp_entity_id
108
111
  issuer = root.add_element "saml:Issuer", { "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
@@ -42,6 +42,8 @@ module OneLogin
42
42
  end
43
43
  end
44
44
 
45
+ alias nameid name_id
46
+
45
47
  def sessionindex
46
48
  @sessionindex ||= begin
47
49
  node = xpath_first_from_signed_assertion('/a:AuthnStatement')
@@ -147,6 +149,9 @@ module OneLogin
147
149
  end
148
150
 
149
151
  def validate(soft = true)
152
+ validate_success_status &&
153
+ validate_num_assertion &&
154
+ validate_signed_elements &&
150
155
  validate_structure(soft) &&
151
156
  validate_response_state(soft) &&
152
157
  validate_conditions(soft) &&
@@ -155,6 +160,144 @@ module OneLogin
155
160
  success?
156
161
  end
157
162
 
163
+ # Validates that the SAML Response only contains a single Assertion (encrypted or not).
164
+ # @return [Boolean] True if the SAML Response contains one unique Assertion, otherwise False
165
+ #
166
+ def validate_num_assertion(soft = true)
167
+ assertions = REXML::XPath.match(
168
+ document,
169
+ "//a:Assertion",
170
+ { "a" => ASSERTION }
171
+ )
172
+ encrypted_assertions = REXML::XPath.match(
173
+ document,
174
+ "//a:EncryptedAssertion",
175
+ { "a" => ASSERTION }
176
+ )
177
+
178
+ unless assertions.size != 0
179
+ return soft ? false : validation_error("Encrypted assertion is not supported")
180
+ end
181
+
182
+ unless assertions.size + encrypted_assertions.size == 1
183
+ return soft ? false : validation_error("SAML Response must contain 1 assertion")
184
+ end
185
+
186
+ true
187
+ end
188
+
189
+ # Validates the Signed elements
190
+ # @return [Boolean] True if there is 1 or 2 Elements signed in the SAML Response
191
+ # an are a Response or an Assertion Element, otherwise False if soft=True
192
+ #
193
+ def validate_signed_elements
194
+ signature_nodes = REXML::XPath.match(
195
+ document,
196
+ "//ds:Signature",
197
+ {"ds"=>DSIG}
198
+ )
199
+ signed_elements = []
200
+ verified_seis = []
201
+ verified_ids = []
202
+ signature_nodes.each do |signature_node|
203
+ signed_element = signature_node.parent.name
204
+ if signed_element != 'Response' && signed_element != 'Assertion'
205
+ return soft ? false : validation_error("Invalid Signature Element '#{signed_element}'. SAML Response rejected")
206
+ end
207
+
208
+ if signature_node.parent.attributes['ID'].nil?
209
+ return soft ? false : validation_error("Signed Element must contain an ID. SAML Response rejected")
210
+ end
211
+
212
+ id = signature_node.parent.attributes.get_attribute("ID").value
213
+ if verified_ids.include?(id)
214
+ return soft ? false : validation_error("Duplicated ID. SAML Response rejected")
215
+ end
216
+ verified_ids.push(id)
217
+
218
+ # Check that reference URI matches the parent ID and no duplicate References or IDs
219
+ ref = REXML::XPath.first(signature_node, ".//ds:Reference", {"ds"=>DSIG})
220
+ if ref
221
+ uri = ref.attributes.get_attribute("URI")
222
+ if uri && !uri.value.empty?
223
+ sei = uri.value[1..-1]
224
+
225
+ unless sei == id
226
+ return soft ? false : validation_error("Found an invalid Signed Element. SAML Response rejected")
227
+ end
228
+
229
+ if verified_seis.include?(sei)
230
+ return soft ? false : validation_error("Duplicated Reference URI. SAML Response rejected")
231
+ return append_error("Duplicated Reference URI. SAML Response rejected")
232
+ end
233
+
234
+ verified_seis.push(sei)
235
+ end
236
+ end
237
+
238
+ signed_elements << signed_element
239
+ end
240
+
241
+ unless signature_nodes.length < 3 && !signed_elements.empty?
242
+ return soft ? false : validation_error("Found an unexpected number of Signature Element. SAML Response rejected")
243
+ end
244
+
245
+ true
246
+ end
247
+
248
+ # Validates the Status of the SAML Response
249
+ # @return [Boolean] True if the SAML Response contains a Success code, otherwise False if soft == false
250
+ # @raise [ValidationError] if soft == false and validation fails
251
+ #
252
+ def validate_success_status
253
+ return true if success?
254
+
255
+ return false unless soft
256
+
257
+ error_msg = 'The status code of the Response was not Success'
258
+ status_error_msg = OneLogin::RubySaml::Utils.status_error_msg(error_msg, status_code, status_message)
259
+ return validation_error(status_error_msg)
260
+ end
261
+
262
+ # Checks if the Status has the "Success" code
263
+ # @return [Boolean] True if the StatusCode is Sucess
264
+ #
265
+ def success?
266
+ status_code == "urn:oasis:names:tc:SAML:2.0:status:Success"
267
+ end
268
+
269
+ # @return [String] StatusCode value from a SAML Response.
270
+ #
271
+ def status_code
272
+ @status_code ||= begin
273
+ nodes = REXML::XPath.match(
274
+ document,
275
+ "/p:Response/p:Status/p:StatusCode",
276
+ { "p" => PROTOCOL }
277
+ )
278
+ if nodes.size == 1
279
+ node = nodes[0]
280
+ code = node.attributes["Value"] if node && node.attributes
281
+
282
+ unless code == "urn:oasis:names:tc:SAML:2.0:status:Success"
283
+ nodes = REXML::XPath.match(
284
+ document,
285
+ "/p:Response/p:Status/p:StatusCode/p:StatusCode",
286
+ { "p" => PROTOCOL }
287
+ )
288
+ statuses = nodes.collect do |inner_node|
289
+ inner_node.attributes["Value"]
290
+ end
291
+ extra_code = statuses.join(" | ")
292
+ if extra_code
293
+ code = "#{code} | #{extra_code}"
294
+ end
295
+ end
296
+ code
297
+ end
298
+ end
299
+ end
300
+
158
301
  def validate_structure(soft = true)
159
302
  Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
160
303
  @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
@@ -0,0 +1,6 @@
1
+ module OneLogin
2
+ module RubySaml
3
+ class SettingError < StandardError
4
+ end
5
+ end
6
+ end
@@ -2,6 +2,7 @@ require "base64"
2
2
  require "zlib"
3
3
  require "cgi"
4
4
  require "onelogin/ruby-saml/utils"
5
+ require "onelogin/ruby-saml/setting_error"
5
6
 
6
7
  module OneLogin
7
8
  module RubySaml
@@ -35,7 +36,7 @@ module OneLogin
35
36
  params.each_pair do |key, value|
36
37
  response_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
37
38
  end
38
-
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?
39
40
  @logout_url = settings.idp_slo_target_url + response_params
40
41
  end
41
42
 
@@ -119,7 +120,7 @@ module OneLogin
119
120
  root.attributes['IssueInstant'] = time
120
121
  root.attributes['Version'] = '2.0'
121
122
  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
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
123
124
 
124
125
  if settings.sp_entity_id != nil
125
126
  issuer = root.add_element "saml:Issuer"
@@ -89,6 +89,31 @@ module OneLogin
89
89
  def self.uuid
90
90
  RUBY_VERSION < '1.9' ? "_#{@@uuid_generator.generate}" : "_#{SecureRandom.uuid}"
91
91
  end
92
+
93
+ # Build the status error message
94
+ # @param status_code [String] StatusCode value
95
+ # @param status_message [Strig] StatusMessage value
96
+ # @return [String] The status error message
97
+ def self.status_error_msg(error_msg, raw_status_code = nil, status_message = nil)
98
+ unless raw_status_code.nil?
99
+ if raw_status_code.include? "|"
100
+ status_codes = raw_status_code.split(' | ')
101
+ values = status_codes.collect do |status_code|
102
+ status_code.split(':').last
103
+ end
104
+ printable_code = values.join(" => ")
105
+ else
106
+ printable_code = raw_status_code.split(':').last
107
+ end
108
+ error_msg << ', was ' + printable_code
109
+ end
110
+
111
+ unless status_message.nil?
112
+ error_msg << ' -> ' + status_message
113
+ end
114
+
115
+ error_msg
116
+ end
92
117
  end
93
118
  end
94
119
  end
@@ -1,5 +1,5 @@
1
1
  module OneLogin
2
2
  module RubySaml
3
- VERSION = '0.8.10'
3
+ VERSION = '0.8.11'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-saml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.10
4
+ version: 0.8.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - OneLogin LLC
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-25 00:00:00.000000000 Z
11
+ date: 2019-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: uuid
@@ -61,6 +61,7 @@ files:
61
61
  - lib/onelogin/ruby-saml/logoutresponse.rb
62
62
  - lib/onelogin/ruby-saml/metadata.rb
63
63
  - lib/onelogin/ruby-saml/response.rb
64
+ - lib/onelogin/ruby-saml/setting_error.rb
64
65
  - lib/onelogin/ruby-saml/settings.rb
65
66
  - lib/onelogin/ruby-saml/slo_logoutresponse.rb
66
67
  - lib/onelogin/ruby-saml/utils.rb
@@ -127,7 +128,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
128
  - !ruby/object:Gem::Version
128
129
  version: '0'
129
130
  requirements: []
130
- rubygems_version: 3.0.4
131
+ rubyforge_project: http://www.rubygems.org/gems/ruby-saml
132
+ rubygems_version: 2.5.1
131
133
  signing_key:
132
134
  specification_version: 4
133
135
  summary: SAML Ruby Tookit