@@ -276,70 +276,64 @@ def post_xml(xml = :example_response, opts = {})
276276 end
277277
278278 context "when response is a logout response" do
279- before :each do
280- post "/auth/saml/slo" , {
279+ let ( :opts ) do
280+ { "rack.session" => { "saml_transaction_id" => "_3fef1069-d0c6-418a-b68d-6f008a4787e9" } }
281+ end
282+
283+ let ( :params ) do
284+ {
281285 SAMLResponse : load_xml ( :example_logout_response ) ,
282- RelayState : "https://example.com/" ,
283- } , "rack.session" => { "saml_transaction_id" => "_3fef1069-d0c6-418a-b68d-6f008a4787e9" }
286+ RelayState : relay_state ,
287+ }
284288 end
285289
286- it "should redirect to relaystate" do
287- expect ( last_response ) . to be_redirect
288- expect ( last_response . location ) . to match /https:\/ \/ example.com\/ /
290+ subject ( :post_slo_response ) { post "/auth/saml/slo" , params , opts }
291+
292+ context "when relay state is relative" do
293+ let ( :relay_state ) { "/signed-out" }
294+
295+ it "redirects to the relaystate" do
296+ post_slo_response
297+
298+ expect ( last_response ) . to be_redirect
299+ expect ( last_response . location ) . to eq "/signed-out"
300+ end
301+ end
302+
303+ context "when relay state is an absolute https URL" do
304+ let ( :relay_state ) { "https://example.com/" }
305+
306+ it "raises an invalid relay state error" do
307+ expect { post_slo_response } .
308+ to raise_error ( OmniAuth ::Strategies ::SAML ::ValidationError , "Invalid RelayState" )
309+ end
289310 end
290311
291312 context 'when slo_default_relay_state is present' do
292313 let ( :saml_options ) { super ( ) . merge ( slo_default_relay_state : '/signed-out' ) }
293314
294315 context "when response relay state is invalid" do
295- let ( :params ) do
296- {
297- SAMLResponse : load_xml ( :example_logout_response ) ,
298- RelayState : "https://example.com/" ,
299- }
300- end
301-
302- let ( :opts ) do
303- { "rack.session" => { "saml_transaction_id" => "_3fef1069-d0c6-418a-b68d-6f008a4787e9" } }
304- end
305-
306- subject ( :post_slo_response ) { post "/auth/saml/slo" , params , opts }
316+ let ( :relay_state ) { "https://example.com/" }
307317
308318 [
309319 "//attacker.test" ,
310320 "javascript:alert(1)" ,
321+ "https://example.com/logout" ,
311322 ] . each do |unsafe_relay_state |
312323 context "#{ unsafe_relay_state } " do
313- let ( :params ) { super ( ) . merge ( RelayState : unsafe_relay_state ) }
324+ let ( :relay_state ) { unsafe_relay_state }
314325
315326 it { is_expected . to be_redirect . and have_attributes ( location : "/signed-out" ) }
316327 end
317328 end
318-
319- context 'when absolute https relay state' do
320- let ( :params ) { super ( ) . merge ( RelayState : "https://example.com/logout" ) }
321-
322- it { is_expected . to be_redirect . and have_attributes ( location : "https://example.com/logout" ) }
323- end
324329 end
325330 end
326331
327332 context 'when slo_default_relay_state is blank' do
328333 let ( :saml_options ) { super ( ) . merge ( slo_default_relay_state : nil ) }
329334
330335 context "when response relay state is invalid" do
331- let ( :params ) do
332- {
333- SAMLResponse : load_xml ( :example_logout_response ) ,
334- RelayState : "javascript:alert(1)" ,
335- }
336- end
337-
338- let ( :opts ) do
339- { "rack.session" => { "saml_transaction_id" => "_3fef1069-d0c6-418a-b68d-6f008a4787e9" } }
340- end
341-
342- subject ( :post_slo_response ) { post "/auth/saml/slo" , params , opts }
336+ let ( :relay_state ) { "javascript:alert(1)" }
343337
344338 it { expect { post_slo_response } . to raise_error ( OmniAuth ::Strategies ::SAML ::ValidationError , "Invalid RelayState" ) }
345339 end
@@ -349,27 +343,33 @@ def post_xml(xml = :example_response, opts = {})
349343 context "when request is a logout request" do
350344 subject { post "/auth/saml/slo" , params , "rack.session" => { "saml_uid" => "[email protected] " } } 351345
346+ let ( :relay_state ) { "https://example.com/" }
347+
352348 let ( :params ) do
353349 {
354350 "SAMLRequest" => load_xml ( :example_logout_request ) ,
355- "RelayState" => "https://example.com/" ,
351+ "RelayState" => relay_state ,
356352 }
357353 end
358354
359355 context "when logout request is valid" do
356+ let ( :relay_state ) { "/logout" }
357+
360358 before { subject }
361359
362360 it "should redirect to logout response" do
363361 expect ( last_response ) . to be_redirect
364362 expect ( last_response . location ) . to match /https:\/ \/ idp.sso.example.com\/ signoff\/ 29490/
365- expect ( last_response . location ) . to match /RelayState=https%3A%2F%2Fexample.com%2F /
363+ expect ( last_response . location ) . to match /RelayState=%2Flogout /
366364 end
367365 end
368366
369367 context 'when slo_default_relay_state is present' do
370368 let ( :saml_options ) { super ( ) . merge ( slo_default_relay_state : '/signed-out' ) }
371369
372370 context "when request relay state is invalid" do
371+ let ( :relay_state ) { "https://example.com/" }
372+
373373 let ( :params ) do
374374 {
375375 "SAMLRequest" => load_xml ( :example_logout_request ) ,
@@ -380,6 +380,7 @@ def post_xml(xml = :example_response, opts = {})
380380 [
381381 "//attacker.test" ,
382382 "javascript:alert(1)" ,
383+ "https://example.com/logout" ,
383384 ] . each do |unsafe_relay_state |
384385 context "when the relay state is #{ unsafe_relay_state } " do
385386 let ( :relay_state ) { unsafe_relay_state }
@@ -397,11 +398,6 @@ def post_xml(xml = :example_response, opts = {})
397398 it { is_expected . to be_redirect . and have_attributes ( location : a_string_matching ( /RelayState=%2Fsigned-out/ ) ) }
398399 end
399400
400- context "when the relay state is an https URL" do
401- let ( :relay_state ) { "https://example.com/logout" }
402-
403- it { is_expected . to have_attributes ( location : a_string_matching ( /RelayState=https%3A%2F%2Fexample.com%2Flogout/ ) ) }
404- end
405401 end
406402
407403 context "with validators that resolve to falsy" do
@@ -540,15 +536,15 @@ def test_default_relay_state(static_default_relay_state = nil, &block_default_re
540536 end
541537 end
542538
543- context 'when slo_default_relay_state is present' do
544- let ( :saml_options ) { super ( ) . merge ( slo_default_relay_state : '/signed-out' ) }
545- let ( :params ) { { } }
546- subject { post "/auth/saml/spslo" , params }
539+ context 'when slo_default_relay_state is present' do
540+ let ( :saml_options ) { super ( ) . merge ( slo_default_relay_state : '/signed-out' ) }
541+ let ( :params ) { { } }
542+ subject { post "/auth/saml/spslo" , params }
547543
548544 context 'with an https relay state' do
549545 let ( :params ) { { RelayState : "https://example.com/logout" } }
550546
551- it { is_expected . to be_redirect . and have_attributes ( location : a_string_matching ( /RelayState=https%3A%2F%2Fexample.com%2Flogout / ) ) }
547+ it { is_expected . to be_redirect . and have_attributes ( location : a_string_matching ( /RelayState=%2Fsigned-out / ) ) }
552548 end
553549
554550 context 'with a protocol relative relay state' do
0 commit comments