require File.expand_path(File.join(File.dirname(__FILE__), "test_helper")) require 'onelogin/ruby-saml/authrequest' require 'onelogin/ruby-saml/setting_error' class RequestTest < Minitest::Test describe "Authrequest" do let(:settings) { OneLogin::RubySaml::Settings.new } before do settings.idp_sso_service_url = "http://example.com" end it "create the deflated SAMLRequest URL parameter" do auth_url = OneLogin::RubySaml::Authrequest.new.create(settings) assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url payload = CGI.unescape(auth_url.split("=").last) decoded = Base64.decode64(payload) zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS) inflated = zstream.inflate(decoded) zstream.finish zstream.close assert_match /^') assert inflated.include?("testuser@example.com") assert inflated.include?("") end it "accept extra parameters" do auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :hello => "there" }) assert_match /&hello=there$/, auth_url auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :hello => nil }) assert_match /&hello=$/, auth_url end it "RelayState cases" do auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :RelayState => nil }) assert !auth_url.include?('RelayState') auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :RelayState => "http://example.com" }) assert auth_url.include?('&RelayState=http%3A%2F%2Fexample.com') auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { 'RelayState' => nil }) assert !auth_url.include?('RelayState') auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { 'RelayState' => "http://example.com" }) assert auth_url.include?('&RelayState=http%3A%2F%2Fexample.com') end it "creates request with ID prefixed with default '_'" do request = OneLogin::RubySaml::Authrequest.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::Authrequest.new assert_match /^test/, request.uuid OneLogin::RubySaml::Utils::set_prefix("_") end describe "when the target url is not set" do before do settings.idp_sso_service_url = nil end it "raises an error with a descriptive message" do err = assert_raises OneLogin::RubySaml::SettingError do OneLogin::RubySaml::Authrequest.new.create(settings) end assert_match /idp_sso_service_url is not set/, err.message end end describe "when the target url doesn't contain a query string" do it "create the SAMLRequest parameter correctly" do auth_url = OneLogin::RubySaml::Authrequest.new.create(settings) assert_match /^http:\/\/example.com\?SAMLRequest/, auth_url end end describe "when the target url contains a query string" do it "create the SAMLRequest parameter correctly" do settings.idp_sso_service_url = "http://example.com?field=value" auth_url = OneLogin::RubySaml::Authrequest.new.create(settings) assert_match /^http:\/\/example.com\?field=value&SAMLRequest/, auth_url end end it "create the saml:AuthnContextClassRef element correctly" do settings.authn_context = 'secure/name/password/uri' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert_match /secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s end it "create multiple saml:AuthnContextClassRef elements correctly" do settings.authn_context = ['secure/name/password/uri', 'secure/email/password/uri'] auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert_match /secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s assert_match /secure\/email\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s end it "create the saml:AuthnContextClassRef with comparison exact" do settings.authn_context = 'secure/name/password/uri' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert_match /secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s end it "create the saml:AuthnContextClassRef with comparison minimun" do settings.authn_context = 'secure/name/password/uri' settings.authn_context_comparison = 'minimun' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert_match /secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s end it "create the saml:AuthnContextDeclRef element correctly" do settings.authn_context_decl_ref = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert_match /urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport<\/saml:AuthnContextDeclRef>/, auth_doc.to_s end describe "#create_params signing with HTTP-POST binding" do before do settings.compress_request = false settings.idp_sso_service_url = "http://example.com?field=value" settings.idp_sso_service_binding = :post settings.security[:authn_requests_signed] = true settings.certificate = ruby_saml_cert_text settings.private_key = ruby_saml_key_text end it "create a signed request" do params = OneLogin::RubySaml::Authrequest.new.create_params(settings) request_xml = Base64.decode64(params["SAMLRequest"]) assert_match %r[([a-zA-Z0-9/+=]+)], request_xml assert_match %r[], request_xml end it "create a signed request with 256 digest and signature methods" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256 settings.security[:digest_method] = XMLSecurity::Document::SHA512 params = OneLogin::RubySaml::Authrequest.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 "#create_params signing with HTTP-Redirect binding" do let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) } before do settings.compress_request = false settings.idp_sso_service_url = "http://example.com?field=value" settings.idp_sso_service_binding = :redirect settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" settings.security[:authn_requests_signed] = true settings.certificate = ruby_saml_cert_text settings.private_key = ruby_saml_key_text end it "create a signature parameter with RSA_SHA1 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1 params = OneLogin::RubySaml::Authrequest.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 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256 params = OneLogin::RubySaml::Authrequest.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 end it "create the saml:AuthnContextClassRef element correctly" do settings.authn_context = 'secure/name/password/uri' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert auth_doc.to_s =~ /secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/ end it "create the saml:AuthnContextClassRef with comparison exact" do settings.authn_context = 'secure/name/password/uri' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert auth_doc.to_s =~ /secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/ end it "create the saml:AuthnContextClassRef with comparison minimun" do settings.authn_context = 'secure/name/password/uri' settings.authn_context_comparison = 'minimun' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert auth_doc.to_s =~ /secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/ end it "create the saml:AuthnContextDeclRef element correctly" do settings.authn_context_decl_ref = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport' auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert auth_doc.to_s =~ /urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport<\/saml:AuthnContextDeclRef>/ end it "create multiple saml:AuthnContextDeclRef elements correctly " do settings.authn_context_decl_ref = ['name/password/uri', 'example/decl/ref'] auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings) assert auth_doc.to_s =~ /name\/password\/uri<\/saml:AuthnContextDeclRef>/ assert auth_doc.to_s =~ /example\/decl\/ref<\/saml:AuthnContextDeclRef>/ end describe "DEPRECATED: #create_params signing with HTTP-POST binding via :embed_sign" do before do settings.compress_request = false settings.idp_sso_service_url = "http://example.com?field=value" settings.security[:authn_requests_signed] = true settings.security[:embed_sign] = true settings.certificate = ruby_saml_cert_text settings.private_key = ruby_saml_key_text end it "create a signed request" do params = OneLogin::RubySaml::Authrequest.new.create_params(settings) request_xml = Base64.decode64(params["SAMLRequest"]) assert_match %r[([a-zA-Z0-9/+=]+)], request_xml assert_match %r[], request_xml end end describe "DEPRECATED: #create_params signing with HTTP-Redirect binding via :embed_sign" do let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) } before do settings.compress_request = false settings.idp_sso_service_url = "http://example.com?field=value" settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" settings.security[:authn_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 and validate it" do settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1 params = OneLogin::RubySaml::Authrequest.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 authnrequest = OneLogin::RubySaml::Authrequest.new request_id = authnrequest.request_id assert_equal request_id, authnrequest.uuid authnrequest.uuid = "new_uuid" assert_equal authnrequest.request_id, authnrequest.uuid assert_equal "new_uuid", authnrequest.request_id end end end end