<commit_before>require 'rails_helper'

describe Devise::Strategies::SamlAuthenticatable do
  subject(:strategy) { described_class.new(env, :user) }
  let(:env) { {} }
  let(:errors) { ["Test1", "Test2"] }

  let(:response) { double(:response, issuers: [idp_entity_id], :settings= => nil, is_valid?: true, sessionindex: '123123123', errors: errors) }
  let(:idp_entity_id) { "https://test/saml/metadata/123123" }
  before do
    allow(OneLogin::RubySaml::Response).to receive(:new).and_return(response)
  end

  let(:mapping) { double(:mapping, to: user_class) }
  let(:user_class) { double(:user_class, authenticate_with_saml: user) }
  let(:user) { double(:user) }
  before do
    allow(strategy).to receive(:mapping).and_return(mapping)
    allow(user).to receive(:after_saml_authentication)
  end

  let(:params) { {} }
  before do
    allow(strategy).to receive(:params).and_return(params)
  end

  context "with a login SAMLResponse parameter" do
    let(:params) { {SAMLResponse: "<KEY>} }

    it "is valid" do
      expect(strategy).to be_valid
    end

    it "authenticates with the response" do
      expect(OneLogin::RubySaml::Response).to receive(:new).with(params[:SAMLResponse], anything)
      expect(user_class).to receive(:authenticate_with_saml).with(response)
      expect(user).to receive(:after_saml_authentication).with(response.sessionindex)

      expect(strategy).to receive(:success!).with(user)
      strategy.authenticate!
    end

    context "when saml config uses an idp_adapter" do
      let(:idp_providers_adapter) {
        Class.new {
          def self.settings(idp_entity_id)
            {
              assertion_consumer_service_url: "acs_url",
              assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
              name_identifier_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
              issuer: "sp_issuer",
              idp_entity_id: "http://www.example.com",
              authn_context: "",
              idp_slo_target_url: "idp_slo_url",
              idp_sso_target_url: "http://idp_sso_url",
              idp_cert: "idp_cert"
            }
          end
        }
      }

      before do
        Devise.idp_settings_adapter = idp_providers_adapter
        allow(idp_providers_adapter).to receive(:settings).and_return({})
      end

      it "is valid" do
        expect(strategy).to be_valid
      end

      it "authenticates with the response for the corresponding idp" do
        expect(OneLogin::RubySaml::Response).to receive(:new).with(params[:SAMLResponse], anything)
        expect(idp_providers_adapter).to receive(:settings).with(idp_entity_id)
        expect(user_class).to receive(:authenticate_with_saml).with(response)
        expect(user).to receive(:after_saml_authentication).with(response.sessionindex)

        expect(strategy).to receive(:success!).with(user)
        strategy.authenticate!
      end
    end

    context "and the resource does not exist" do
      let(:user) { nil }

      it "fails to authenticate" do
        expect(strategy).to receive(:fail!).with(:invalid)
        strategy.authenticate!
      end

      it 'logs the error' do
        expect(DeviseSamlAuthenticatable::Logger).to receive(:send).with('Resource could not be found')
        strategy.authenticate!
      end
    end

    context "and the SAML response is not valid" do
      class CallbackHandler
        def handle(response, strategy)
        end
      end

      before do
        allow(response).to receive(:is_valid?).and_return(false)
        @saml_failed_login = Devise.saml_failed_callback
        Devise.saml_failed_callback = CallbackHandler
      end

      after do
        Devise.saml_failed_callback = @saml_failed_login
      end

      it 'logs the error' do
        expect(DeviseSamlAuthenticatable::Logger).to receive(:send).with('Auth errors: Test1, Test2')
        strategy.authenticate!
      end

      it "fails to authenticate" do
        expect(strategy).to receive(:fail!).with(:invalid)
        strategy.authenticate!
      end

      it "redirects" do
        expect_any_instance_of(CallbackHandler).to receive(:handle).with(response, strategy)
        strategy.authenticate!
      end
    end
  end

  it "is not valid without a SAMLResponse parameter" do
    expect(strategy).not_to be_valid
  end

  it "is permanent" do
    expect(strategy).to be_store
  end
end<commit_msg>Update specs for strategy storage<commit_after>require 'rails_helper'

describe Devise::Strategies::SamlAuthenticatable do
  subject(:strategy) { described_class.new(env, :user) }
  let(:env) { {} }
  let(:errors) { ["Test1", "Test2"] }

  let(:response) { double(:response, issuers: [idp_entity_id], :settings= => nil, is_valid?: true, sessionindex: '123123123', errors: errors) }
  let(:idp_entity_id) { "https://test/saml/metadata/123123" }
  before do
    allow(OneLogin::RubySaml::Response).to receive(:new).and_return(response)
  end

  let(:mapping) { double(:mapping, to: user_class) }
  let(:user_class) { double(:user_class, authenticate_with_saml: user, skip_session_storage: []) }
  let(:user) { double(:user) }
  before do
    allow(strategy).to receive(:mapping).and_return(mapping)
    allow(user).to receive(:after_saml_authentication)
  end

  let(:params) { {} }
  before do
    allow(strategy).to receive(:params).and_return(params)
  end

  context "with a login SAMLResponse parameter" do
    let(:params) { {SAMLResponse: "<KEY>} }

    it "is valid" do
      expect(strategy).to be_valid
    end

    it "authenticates with the response" do
      expect(OneLogin::RubySaml::Response).to receive(:new).with(params[:SAMLResponse], anything)
      expect(user_class).to receive(:authenticate_with_saml).with(response)
      expect(user).to receive(:after_saml_authentication).with(response.sessionindex)

      expect(strategy).to receive(:success!).with(user)
      strategy.authenticate!
    end

    context "when saml config uses an idp_adapter" do
      let(:idp_providers_adapter) {
        Class.new {
          def self.settings(idp_entity_id)
            {
              assertion_consumer_service_url: "acs_url",
              assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
              name_identifier_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
              issuer: "sp_issuer",
              idp_entity_id: "http://www.example.com",
              authn_context: "",
              idp_slo_target_url: "idp_slo_url",
              idp_sso_target_url: "http://idp_sso_url",
              idp_cert: "idp_cert"
            }
          end
        }
      }

      before do
        Devise.idp_settings_adapter = idp_providers_adapter
        allow(idp_providers_adapter).to receive(:settings).and_return({})
      end

      it "is valid" do
        expect(strategy).to be_valid
      end

      it "authenticates with the response for the corresponding idp" do
        expect(OneLogin::RubySaml::Response).to receive(:new).with(params[:SAMLResponse], anything)
        expect(idp_providers_adapter).to receive(:settings).with(idp_entity_id)
        expect(user_class).to receive(:authenticate_with_saml).with(response)
        expect(user).to receive(:after_saml_authentication).with(response.sessionindex)

        expect(strategy).to receive(:success!).with(user)
        strategy.authenticate!
      end
    end

    context "and the resource does not exist" do
      let(:user) { nil }

      it "fails to authenticate" do
        expect(strategy).to receive(:fail!).with(:invalid)
        strategy.authenticate!
      end

      it 'logs the error' do
        expect(DeviseSamlAuthenticatable::Logger).to receive(:send).with('Resource could not be found')
        strategy.authenticate!
      end
    end

    context "and the SAML response is not valid" do
      class CallbackHandler
        def handle(response, strategy)
        end
      end

      before do
        allow(response).to receive(:is_valid?).and_return(false)
        @saml_failed_login = Devise.saml_failed_callback
        Devise.saml_failed_callback = CallbackHandler
      end

      after do
        Devise.saml_failed_callback = @saml_failed_login
      end

      it 'logs the error' do
        expect(DeviseSamlAuthenticatable::Logger).to receive(:send).with('Auth errors: Test1, Test2')
        strategy.authenticate!
      end

      it "fails to authenticate" do
        expect(strategy).to receive(:fail!).with(:invalid)
        strategy.authenticate!
      end

      it "redirects" do
        expect_any_instance_of(CallbackHandler).to receive(:handle).with(response, strategy)
        strategy.authenticate!
      end
    end
  end

  it "is not valid without a SAMLResponse parameter" do
    expect(strategy).not_to be_valid
  end

  it "is permanent" do
    expect(strategy).to be_store
  end

  context "when the user should not be stored in the session" do
    before do
      allow(user_class).to receive(:skip_session_storage).and_return([:saml_auth])
    end

    it "is not stored" do
      expect(strategy).not_to be_store
    end
  end
end
{'fraction_non_alphanumeric': 0.10946196660482375, 'fraction_numerical': 0.005020189894139474, 'mean_word_length': 3.0910714285714285, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3428105', 'n_tokens_mistral': 2936, 'n_tokens_neox': 2802, 'n_words': 570}