require File.expand_path(File.join(File.dirname(__FILE__), "test_helper")) require 'onelogin/ruby-saml/logoutrequest' class RequestTest < Minitest::Test describe "Logoutrequest" do let(:settings) { OneLogin::RubySaml::Settings.new } before do settings.idp_slo_service_url = "http://unauth.com/logout" settings.name_identifier_value = "f00f00" end it "create the deflated SAMLRequest URL parameter" do unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings) assert_match /^http:\/\/unauth\.com\/logout\?SAMLRequest=/, unauth_url inflated = decode_saml_request_payload(unauth_url) assert_match /^ nil }) assert_match /&hello=$/, unauth_url unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :foo => "bar" }) assert_match /&foo=bar$/, unauth_url end it "RelayState cases" do unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :RelayState => nil }) assert !unauth_url.include?('RelayState') unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :RelayState => "http://example.com" }) assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com') unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { 'RelayState' => nil }) assert !unauth_url.include?('RelayState') unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { 'RelayState' => "http://example.com" }) assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com') end it "set sessionindex" do settings.idp_slo_service_url = "http://example.com" sessionidx = OneLogin::RubySaml::Utils.uuid settings.sessionindex = sessionidx unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :nameid => "there" }) inflated = decode_saml_request_payload(unauth_url) assert_match /), inflated end it "set name_identifier_value" do settings.name_identifier_format = "transient" name_identifier_value = "abc123" settings.name_identifier_value = name_identifier_value unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :nameid => "there" }) inflated = decode_saml_request_payload(unauth_url) assert_match /), inflated end describe "when the target url doesn't contain a query string" do it "create the SAMLRequest parameter correctly" do unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings) assert_match /^http:\/\/unauth.com\/logout\?SAMLRequest/, unauth_url end end describe "when the target url contains a query string" do it "create the SAMLRequest parameter correctly" do settings.idp_slo_service_url = "http://example.com?field=value" unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings) assert_match /^http:\/\/example.com\?field=value&SAMLRequest/, unauth_url end end describe "consumation of logout may need to track the transaction" do it "have access to the request uuid" do settings.idp_slo_service_url = "http://example.com?field=value" unauth_req = OneLogin::RubySaml::Logoutrequest.new unauth_url = unauth_req.create(settings) inflated = decode_saml_request_payload(unauth_url) assert_match %r[ID='#{unauth_req.uuid}'], inflated end end describe "playgin with preix" do it "creates request with ID prefixed with default '_'" do request = OneLogin::RubySaml::Logoutrequest.new assert_match /^_/, request.uuid end it "creates request with ID is prefixed, when :id_prefix is passed" do OneLogin::RubySaml::Utils::set_prefix("test") request = OneLogin::RubySaml::Logoutrequest.new assert_match /^test/, request.uuid OneLogin::RubySaml::Utils::set_prefix("_") end end describe "signing with HTTP-POST binding" do before do settings.security[:logout_requests_signed] = true settings.idp_slo_service_binding = :post settings.idp_sso_service_binding = :redirect settings.certificate = ruby_saml_cert_text settings.private_key = ruby_saml_key_text end it "doesn't sign through create_xml_document" do unauth_req = OneLogin::RubySaml::Logoutrequest.new inflated = unauth_req.create_xml_document(settings).to_s refute_match %r[([a-zA-Z0-9/+=]+)], inflated refute_match %r[], inflated refute_match %r[], inflated end it "sign unsigned request" do unauth_req = OneLogin::RubySaml::Logoutrequest.new unauth_req_doc = unauth_req.create_xml_document(settings) inflated = unauth_req_doc.to_s refute_match %r[([a-zA-Z0-9/+=]+)], inflated refute_match %r[], inflated refute_match %r[], inflated inflated = unauth_req.sign_document(unauth_req_doc, settings).to_s assert_match %r[([a-zA-Z0-9/+=]+)], inflated assert_match %r[], inflated assert_match %r[], inflated end it "signs through create_logout_request_xml_doc" do unauth_req = OneLogin::RubySaml::Logoutrequest.new inflated = unauth_req.create_logout_request_xml_doc(settings).to_s assert_match %r[([a-zA-Z0-9/+=]+)], inflated assert_match %r[], inflated assert_match %r[], inflated end it "created a signed logout request" do settings.compress_request = true unauth_req = OneLogin::RubySaml::Logoutrequest.new unauth_url = unauth_req.create(settings) inflated = decode_saml_request_payload(unauth_url) assert_match %r[([a-zA-Z0-9/+=]+)], inflated assert_match %r[], inflated assert_match %r[], inflated end it "create a signed logout request with 256 digest and signature method" do settings.compress_request = false settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256 settings.security[:digest_method] = XMLSecurity::Document::SHA256 params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings) request_xml = Base64.decode64(params["SAMLRequest"]) assert_match %r[([a-zA-Z0-9/+=]+)], request_xml assert_match %r[], request_xml assert_match %r[], request_xml end it "create a signed logout request with 512 digest and signature method RSA_SHA384" do settings.compress_request = false settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384 settings.security[:digest_method] = XMLSecurity::Document::SHA512 params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings) request_xml = Base64.decode64(params["SAMLRequest"]) assert_match %r[([a-zA-Z0-9/+=]+)], request_xml assert_match %r[], request_xml assert_match %r[], request_xml end end describe "signing with HTTP-Redirect binding" do let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) } before do settings.security[:logout_requests_signed] = true settings.idp_slo_service_binding = :redirect settings.idp_sso_service_binding = :post settings.certificate = ruby_saml_cert_text settings.private_key = ruby_saml_key_text end it "create a signature parameter with RSA_SHA1 / SHA1 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1 params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com') assert params['SAMLRequest'] assert params[:RelayState] assert params['Signature'] assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1 query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}" query_string << "&RelayState=#{CGI.escape(params[:RelayState])}" query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}" signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg']) assert_equal signature_algorithm, OpenSSL::Digest::SHA1 assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string) end it "create a signature parameter with RSA_SHA256 / SHA256 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256 params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com') assert params['Signature'] assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256 query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}" query_string << "&RelayState=#{CGI.escape(params[:RelayState])}" query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}" signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg']) assert_equal signature_algorithm, OpenSSL::Digest::SHA256 assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string) end it "create a signature parameter with RSA_SHA384 / SHA384 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384 params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com') assert params['Signature'] assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA384 query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}" query_string << "&RelayState=#{CGI.escape(params[:RelayState])}" query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}" signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg']) assert_equal signature_algorithm, OpenSSL::Digest::SHA384 assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string) end it "create a signature parameter with RSA_SHA512 / SHA512 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA512 params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com') assert params['Signature'] assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA512 query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}" query_string << "&RelayState=#{CGI.escape(params[:RelayState])}" query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}" signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg']) assert_equal signature_algorithm, OpenSSL::Digest::SHA512 assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string) end end describe "DEPRECATED: signing with HTTP-POST binding via :embed_sign" do before do # sign the logout request settings.security[:logout_requests_signed] = true settings.security[:embed_sign] = true settings.certificate = ruby_saml_cert_text settings.private_key = ruby_saml_key_text end it "created a signed logout request" do settings.compress_request = true unauth_req = OneLogin::RubySaml::Logoutrequest.new unauth_url = unauth_req.create(settings) inflated = decode_saml_request_payload(unauth_url) assert_match %r[([a-zA-Z0-9/+=]+)], inflated assert_match %r[], inflated assert_match %r[], inflated end end describe "DEPRECATED: signing with HTTP-Redirect binding via :embed_sign" do let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) } before do settings.security[:logout_requests_signed] = true settings.security[:embed_sign] = false settings.certificate = ruby_saml_cert_text settings.private_key = ruby_saml_key_text end it "create a signature parameter with RSA_SHA1 / SHA1 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1 params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com') assert params['SAMLRequest'] assert params[:RelayState] assert params['Signature'] assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1 query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}" query_string << "&RelayState=#{CGI.escape(params[:RelayState])}" query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}" signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg']) assert_equal signature_algorithm, OpenSSL::Digest::SHA1 assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string) end end describe "#manipulate request_id" do it "be able to modify the request id" do logoutrequest = OneLogin::RubySaml::Logoutrequest.new request_id = logoutrequest.request_id assert_equal request_id, logoutrequest.uuid logoutrequest.uuid = "new_uuid" assert_equal logoutrequest.request_id, logoutrequest.uuid assert_equal "new_uuid", logoutrequest.request_id end end end end