devise_saml_authenticatable 1.3.2 → 1.6.1
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.
- checksums.yaml +5 -5
- data/.gitignore +0 -2
- data/.travis.yml +29 -22
- data/Gemfile +2 -2
- data/README.md +105 -32
- data/app/controllers/devise/saml_sessions_controller.rb +35 -7
- data/devise_saml_authenticatable.gemspec +2 -1
- data/lib/devise_saml_authenticatable.rb +27 -2
- data/lib/devise_saml_authenticatable/default_attribute_map_resolver.rb +26 -0
- data/lib/devise_saml_authenticatable/default_idp_entity_id_reader.rb +2 -0
- data/lib/devise_saml_authenticatable/exception.rb +1 -1
- data/lib/devise_saml_authenticatable/model.rb +16 -18
- data/lib/devise_saml_authenticatable/routes.rb +17 -6
- data/lib/devise_saml_authenticatable/saml_mapped_attributes.rb +15 -2
- data/lib/devise_saml_authenticatable/strategy.rb +1 -0
- data/lib/devise_saml_authenticatable/version.rb +1 -1
- data/spec/controllers/devise/saml_sessions_controller_spec.rb +118 -11
- data/spec/devise_saml_authenticatable/default_attribute_map_resolver_spec.rb +58 -0
- data/spec/devise_saml_authenticatable/model_spec.rb +68 -7
- data/spec/devise_saml_authenticatable/saml_mapped_attributes_spec.rb +50 -0
- data/spec/features/saml_authentication_spec.rb +45 -21
- data/spec/rails_helper.rb +6 -2
- data/spec/routes/routes_spec.rb +102 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/Gemfile.rails4 +23 -6
- data/spec/support/Gemfile.rails5 +13 -2
- data/spec/support/Gemfile.rails5.1 +25 -0
- data/spec/support/Gemfile.rails5.2 +25 -0
- data/spec/support/attribute-map.yml +12 -0
- data/spec/support/attribute_map_resolver.rb.erb +14 -0
- data/spec/support/idp_settings_adapter.rb.erb +5 -5
- data/spec/support/idp_template.rb +6 -2
- data/spec/support/rails_app.rb +75 -17
- data/spec/support/saml_idp_controller.rb.erb +13 -6
- data/spec/support/sp_template.rb +45 -21
- metadata +25 -13
- data/spec/support/Gemfile.ruby-saml-1.3 +0 -24
| @@ -32,6 +32,7 @@ describe Devise::Models::SamlAuthenticatable do | |
| 32 32 | 
             
              end
         | 
| 33 33 |  | 
| 34 34 | 
             
              before do
         | 
| 35 | 
            +
                allow(Devise).to receive(:saml_attribute_map_resolver).and_return(attribute_map_resolver)
         | 
| 35 36 | 
             
                allow(Devise).to receive(:saml_default_user_key).and_return(:email)
         | 
| 36 37 | 
             
                allow(Devise).to receive(:saml_create_user).and_return(false)
         | 
| 37 38 | 
             
                allow(Devise).to receive(:saml_use_subject).and_return(false)
         | 
| @@ -39,13 +40,19 @@ describe Devise::Models::SamlAuthenticatable do | |
| 39 40 |  | 
| 40 41 | 
             
              before do
         | 
| 41 42 | 
             
                allow(Rails).to receive(:root).and_return("/railsroot")
         | 
| 42 | 
            -
                allow(File).to receive(:read).with("/railsroot/config/attribute-map.yml").and_return(<<-ATTRIBUTEMAP)
         | 
| 43 | 
            -
            ---
         | 
| 44 | 
            -
            "saml-email-format": email
         | 
| 45 | 
            -
            "saml-name-format":  name
         | 
| 46 | 
            -
                  ATTRIBUTEMAP
         | 
| 47 43 | 
             
              end
         | 
| 48 44 |  | 
| 45 | 
            +
              let(:attribute_map_resolver) {
         | 
| 46 | 
            +
                Class.new(::DeviseSamlAuthenticatable::DefaultAttributeMapResolver) do
         | 
| 47 | 
            +
                  def attribute_map
         | 
| 48 | 
            +
                    {
         | 
| 49 | 
            +
                      "saml-email-format" => "email",
         | 
| 50 | 
            +
                      "saml-name-format" => "name",
         | 
| 51 | 
            +
                    }
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              }
         | 
| 55 | 
            +
              let(:attributemap) { attribute_map_resolver.new(nil).attribute_map }
         | 
| 49 56 | 
             
              let(:response) { double(:response, attributes: attributes, name_id: name_id) }
         | 
| 50 57 | 
             
              let(:attributes) {
         | 
| 51 58 | 
             
                OneLogin::RubySaml::Attributes.new(
         | 
| @@ -97,6 +104,12 @@ describe Devise::Models::SamlAuthenticatable do | |
| 97 104 | 
             
                    expect(model.name).to  eq('A User')
         | 
| 98 105 | 
             
                    expect(model.saved).to be(true)
         | 
| 99 106 | 
             
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  it "returns nil if it fails to create a user" do
         | 
| 109 | 
            +
                    expect(Model).to receive(:where).with(email: 'user@example.com').and_return([])
         | 
| 110 | 
            +
                    expect(Devise).to receive(:saml_update_resource_hook).and_raise(StandardError.new)
         | 
| 111 | 
            +
                    expect(Model.authenticate_with_saml(response, nil)).to be_nil
         | 
| 112 | 
            +
                  end
         | 
| 100 113 | 
             
                end
         | 
| 101 114 |  | 
| 102 115 | 
             
                context "when configured to update a user and the user is found" do
         | 
| @@ -112,6 +125,13 @@ describe Devise::Models::SamlAuthenticatable do | |
| 112 125 | 
             
                    expect(model.name).to  eq('A User')
         | 
| 113 126 | 
             
                    expect(model.saved).to be(true)
         | 
| 114 127 | 
             
                  end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                  it "returns nil if it fails to update a user" do
         | 
| 130 | 
            +
                    user = Model.new(new_record: false)
         | 
| 131 | 
            +
                    expect(Model).to receive(:where).with(email: 'user@example.com').and_return([user])
         | 
| 132 | 
            +
                    expect(Devise).to receive(:saml_update_resource_hook).and_raise(StandardError.new)
         | 
| 133 | 
            +
                    expect(Model.authenticate_with_saml(response, nil)).to be_nil
         | 
| 134 | 
            +
                  end
         | 
| 115 135 | 
             
                end
         | 
| 116 136 | 
             
              end
         | 
| 117 137 |  | 
| @@ -179,8 +199,8 @@ describe Devise::Models::SamlAuthenticatable do | |
| 179 199 | 
             
                end
         | 
| 180 200 | 
             
              end
         | 
| 181 201 |  | 
| 182 | 
            -
              context "when configured with a resource validator" do
         | 
| 183 | 
            -
                let(:validator_class) { double(" | 
| 202 | 
            +
              context "when configured with a resource validator class" do
         | 
| 203 | 
            +
                let(:validator_class) { double("validator") }
         | 
| 184 204 | 
             
                let(:validator) { double("validator") }
         | 
| 185 205 | 
             
                let(:user) { Model.new(new_record: false) }
         | 
| 186 206 |  | 
| @@ -212,6 +232,41 @@ describe Devise::Models::SamlAuthenticatable do | |
| 212 232 | 
             
                end
         | 
| 213 233 | 
             
              end
         | 
| 214 234 |  | 
| 235 | 
            +
             | 
| 236 | 
            +
              context "when configured with a resource validator hook" do
         | 
| 237 | 
            +
                let(:validator_hook) { double("validator_hook") }
         | 
| 238 | 
            +
                let(:decorated_response) { ::SamlAuthenticatable::SamlResponse.new(response, attributemap) }
         | 
| 239 | 
            +
                let(:user) { Model.new(new_record: false) }
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                before do
         | 
| 242 | 
            +
                  allow(Devise).to receive(:saml_resource_validator_hook).and_return(validator_hook)
         | 
| 243 | 
            +
                  allow(::SamlAuthenticatable::SamlResponse).to receive(:new).with(response, attributemap).and_return(decorated_response)
         | 
| 244 | 
            +
                end
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                context "and sent a valid value" do
         | 
| 247 | 
            +
                  before do
         | 
| 248 | 
            +
                    expect(validator_hook).to receive(:call).with(user, decorated_response, 'user@example.com').and_return(true)
         | 
| 249 | 
            +
                  end
         | 
| 250 | 
            +
             | 
| 251 | 
            +
                  it "returns the user" do
         | 
| 252 | 
            +
                    expect(Model).to receive(:where).with(email: 'user@example.com').and_return([user])
         | 
| 253 | 
            +
                    expect(Model.authenticate_with_saml(response, nil)).to eq(user)
         | 
| 254 | 
            +
                  end
         | 
| 255 | 
            +
                end
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                context "and sent an invalid value" do
         | 
| 258 | 
            +
                  before do
         | 
| 259 | 
            +
                    expect(validator_hook).to receive(:call).with(user, decorated_response, 'user@example.com').and_return(false)
         | 
| 260 | 
            +
                  end
         | 
| 261 | 
            +
             | 
| 262 | 
            +
                  it "returns nil" do
         | 
| 263 | 
            +
                    expect(Model).to receive(:where).with(email: 'user@example.com').and_return([user])
         | 
| 264 | 
            +
                    expect(Model.authenticate_with_saml(response, nil)).to be_nil
         | 
| 265 | 
            +
                  end
         | 
| 266 | 
            +
                end
         | 
| 267 | 
            +
              end
         | 
| 268 | 
            +
             | 
| 269 | 
            +
             | 
| 215 270 | 
             
              context "when configured to use a custom update hook" do
         | 
| 216 271 | 
             
                it "can replicate the default behaviour in a custom hook" do
         | 
| 217 272 | 
             
                  configure_hook do |user, saml_response|
         | 
| @@ -330,4 +385,10 @@ describe Devise::Models::SamlAuthenticatable do | |
| 330 385 | 
             
                  allow(Devise).to receive(:saml_resource_locator).and_return(block)
         | 
| 331 386 | 
             
                end
         | 
| 332 387 | 
             
              end
         | 
| 388 | 
            +
             | 
| 389 | 
            +
              describe "::attribute_map" do
         | 
| 390 | 
            +
                it "returns the attribute map" do
         | 
| 391 | 
            +
                  expect(Model.attribute_map).to eq(attributemap)
         | 
| 392 | 
            +
                end
         | 
| 393 | 
            +
              end
         | 
| 333 394 | 
             
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'devise_saml_authenticatable/saml_mapped_attributes'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe SamlAuthenticatable::SamlMappedAttributes do
         | 
| 5 | 
            +
              let(:instance) { described_class.new(saml_attributes, attribute_map) }
         | 
| 6 | 
            +
              let(:attribute_map_file) { File.join(File.dirname(__FILE__), '../support/attribute-map.yml') }
         | 
| 7 | 
            +
              let(:attribute_map) { YAML.load(File.read(attribute_map_file)) }
         | 
| 8 | 
            +
              let(:saml_attributes) do
         | 
| 9 | 
            +
                {
         | 
| 10 | 
            +
                  "first_name" => ["John"],
         | 
| 11 | 
            +
                  "last_name"=>["Smith"],
         | 
| 12 | 
            +
                  "email"=>["john.smith@example.com"]
         | 
| 13 | 
            +
                }
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              describe "#value_by_resource_key" do
         | 
| 17 | 
            +
                RSpec.shared_examples "correctly maps the value of the resource key" do |saml_key, resource_key, expected_value|
         | 
| 18 | 
            +
                  subject(:perform) { instance.value_by_resource_key(resource_key) }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  it "correctly maps the resource key, #{resource_key}, to the value of the '#{saml_key}' SAML key" do
         | 
| 21 | 
            +
                    saml_attributes[saml_key] = saml_attributes.delete(resource_key)
         | 
| 22 | 
            +
                    expect(perform).to eq(expected_value)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                context "first_name" do
         | 
| 27 | 
            +
                  saml_keys = ['urn:mace:dir:attribute-def:first_name', 'first_name', 'firstName', 'firstname']
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  saml_keys.each do |saml_key|
         | 
| 30 | 
            +
                    include_examples 'correctly maps the value of the resource key', saml_key, 'first_name', ['John']
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                context 'last_name' do
         | 
| 35 | 
            +
                  saml_keys = ['urn:mace:dir:attribute-def:last_name', 'last_name', 'lastName', 'lastname']
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  saml_keys.each do |saml_key|
         | 
| 38 | 
            +
                    include_examples 'correctly maps the value of the resource key', saml_key, 'last_name', ['Smith']
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                context 'email' do
         | 
| 43 | 
            +
                  saml_keys = ['urn:mace:dir:attribute-def:email', 'email_address', 'emailAddress', 'email']
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  saml_keys.each do |saml_key|
         | 
| 46 | 
            +
                    include_examples 'correctly maps the value of the resource key', saml_key, 'email', ['john.smith@example.com']
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -5,6 +5,7 @@ require 'uri' | |
| 5 5 | 
             
            require 'capybara/rspec'
         | 
| 6 6 | 
             
            require 'capybara/poltergeist'
         | 
| 7 7 | 
             
            Capybara.default_driver = :poltergeist
         | 
| 8 | 
            +
            Capybara.server = :webrick
         | 
| 8 9 |  | 
| 9 10 | 
             
            describe "SAML Authentication", type: :feature do
         | 
| 10 11 | 
             
              let(:idp_port) { 8009 }
         | 
| @@ -56,7 +57,7 @@ describe "SAML Authentication", type: :feature do | |
| 56 57 | 
             
                  expect(current_url).to eq("http://localhost:8020/")
         | 
| 57 58 |  | 
| 58 59 | 
             
                  click_on "Log out"
         | 
| 59 | 
            -
                  #confirm the logout response redirected to the SP which in turn attempted to sign  | 
| 60 | 
            +
                  # confirm the logout response redirected to the SP which in turn attempted to sign the user back in
         | 
| 60 61 | 
             
                  expect(current_url).to match(%r(\Ahttp://localhost:8009/saml/auth\?SAMLRequest=))
         | 
| 61 62 |  | 
| 62 63 | 
             
                  # prove user is now signed out
         | 
| @@ -84,8 +85,8 @@ describe "SAML Authentication", type: :feature do | |
| 84 85 | 
             
                  @sp_pid  = start_app('sp',  sp_port)
         | 
| 85 86 | 
             
                end
         | 
| 86 87 | 
             
                after(:each) do
         | 
| 87 | 
            -
                  stop_app(@idp_pid)
         | 
| 88 | 
            -
                  stop_app(@sp_pid)
         | 
| 88 | 
            +
                  stop_app("idp", @idp_pid)
         | 
| 89 | 
            +
                  stop_app("sp", @sp_pid)
         | 
| 89 90 | 
             
                end
         | 
| 90 91 |  | 
| 91 92 | 
             
                it_behaves_like "it authenticates and creates users"
         | 
| @@ -99,8 +100,8 @@ describe "SAML Authentication", type: :feature do | |
| 99 100 | 
             
                  @sp_pid  = start_app('sp',  sp_port)
         | 
| 100 101 | 
             
                end
         | 
| 101 102 | 
             
                after(:each) do
         | 
| 102 | 
            -
                  stop_app(@idp_pid)
         | 
| 103 | 
            -
                  stop_app(@sp_pid)
         | 
| 103 | 
            +
                  stop_app("idp", @idp_pid)
         | 
| 104 | 
            +
                  stop_app("sp", @sp_pid)
         | 
| 104 105 | 
             
                end
         | 
| 105 106 |  | 
| 106 107 | 
             
                it_behaves_like "it authenticates and creates users"
         | 
| @@ -114,8 +115,8 @@ describe "SAML Authentication", type: :feature do | |
| 114 115 | 
             
                  @sp_pid  = start_app('sp',  sp_port)
         | 
| 115 116 | 
             
                end
         | 
| 116 117 | 
             
                after(:each) do
         | 
| 117 | 
            -
                  stop_app(@idp_pid)
         | 
| 118 | 
            -
                  stop_app(@sp_pid)
         | 
| 118 | 
            +
                  stop_app("idp", @idp_pid)
         | 
| 119 | 
            +
                  stop_app("sp", @sp_pid)
         | 
| 119 120 | 
             
                end
         | 
| 120 121 |  | 
| 121 122 | 
             
                it_behaves_like "it authenticates and creates users"
         | 
| @@ -130,33 +131,33 @@ describe "SAML Authentication", type: :feature do | |
| 130 131 | 
             
                  @sp_pid  = start_app('sp',  sp_port)
         | 
| 131 132 | 
             
                end
         | 
| 132 133 | 
             
                after(:each) do
         | 
| 133 | 
            -
                  stop_app(@idp_pid)
         | 
| 134 | 
            -
                  stop_app(@sp_pid)
         | 
| 134 | 
            +
                  stop_app("idp", @idp_pid)
         | 
| 135 | 
            +
                  stop_app("sp", @sp_pid)
         | 
| 135 136 | 
             
                end
         | 
| 136 137 |  | 
| 137 138 | 
             
                it_behaves_like "it authenticates and creates users"
         | 
| 138 139 | 
             
              end
         | 
| 139 140 |  | 
| 140 141 | 
             
              context "when the idp_settings_adapter key is set" do
         | 
| 141 | 
            -
             | 
| 142 142 | 
             
                before(:each) do
         | 
| 143 143 | 
             
                  create_app('idp', 'INCLUDE_SUBJECT_IN_ATTRIBUTES' => "false")
         | 
| 144 144 | 
             
                  create_app('sp', 'USE_SUBJECT_TO_AUTHENTICATE' => "true", 'IDP_SETTINGS_ADAPTER' => "IdpSettingsAdapter", 'IDP_ENTITY_ID_READER' => "OurEntityIdReader")
         | 
| 145 145 |  | 
| 146 | 
            -
                   | 
| 146 | 
            +
                  # use a different port for this entity ID; configured in spec/support/idp_settings_adapter.rb.erb
         | 
| 147 | 
            +
                  @idp_pid = start_app('idp', 8010)
         | 
| 147 148 | 
             
                  @sp_pid  = start_app('sp',  sp_port)
         | 
| 148 149 | 
             
                end
         | 
| 149 150 |  | 
| 150 151 | 
             
                after(:each) do
         | 
| 151 | 
            -
                  stop_app(@idp_pid)
         | 
| 152 | 
            -
                  stop_app(@sp_pid)
         | 
| 152 | 
            +
                  stop_app("idp", @idp_pid)
         | 
| 153 | 
            +
                  stop_app("sp", @sp_pid)
         | 
| 153 154 | 
             
                end
         | 
| 154 155 |  | 
| 155 156 | 
             
                it "authenticates an existing user on a SP via an IdP" do
         | 
| 156 157 | 
             
                  create_user("you@example.com")
         | 
| 157 158 |  | 
| 158 159 | 
             
                  visit 'http://localhost:8020/users/saml/sign_in/?entity_id=http%3A%2F%2Flocalhost%3A8020%2Fsaml%2Fmetadata'
         | 
| 159 | 
            -
                  expect(current_url).to match(%r(\Ahttp:// | 
| 160 | 
            +
                  expect(current_url).to match(%r(\Ahttp://localhost:8010/saml/auth\?SAMLRequest=))
         | 
| 160 161 | 
             
                end
         | 
| 161 162 | 
             
              end
         | 
| 162 163 |  | 
| @@ -171,8 +172,8 @@ describe "SAML Authentication", type: :feature do | |
| 171 172 | 
             
                end
         | 
| 172 173 |  | 
| 173 174 | 
             
                after(:each) do
         | 
| 174 | 
            -
                  stop_app(@idp_pid)
         | 
| 175 | 
            -
                  stop_app(@sp_pid)
         | 
| 175 | 
            +
                  stop_app("idp", @idp_pid)
         | 
| 176 | 
            +
                  stop_app("sp", @sp_pid)
         | 
| 176 177 | 
             
                end
         | 
| 177 178 |  | 
| 178 179 | 
             
                it_behaves_like "it authenticates and creates users"
         | 
| @@ -187,24 +188,47 @@ describe "SAML Authentication", type: :feature do | |
| 187 188 | 
             
                    fill_in "Email", with: "you@example.com"
         | 
| 188 189 | 
             
                    fill_in "Password", with: "asdf"
         | 
| 189 190 | 
             
                    click_on "Sign in"
         | 
| 190 | 
            -
                    expect(page).to have_content("Example Domain This domain is  | 
| 191 | 
            +
                    expect(page).to have_content(:all, "Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.")
         | 
| 191 192 | 
             
                    expect(current_url).to eq("http://www.example.com/")
         | 
| 192 193 | 
             
                  end
         | 
| 193 194 | 
             
                end
         | 
| 194 195 | 
             
              end
         | 
| 195 196 |  | 
| 197 | 
            +
              context "when the saml_attribute_map is set" do
         | 
| 198 | 
            +
                before(:each) do
         | 
| 199 | 
            +
                  create_app(
         | 
| 200 | 
            +
                    "idp",
         | 
| 201 | 
            +
                    "EMAIL_ADDRESS_ATTRIBUTE_KEY" => "myemailaddress",
         | 
| 202 | 
            +
                    "NAME_ATTRIBUTE_KEY" => "myname",
         | 
| 203 | 
            +
                    "INCLUDE_SUBJECT_IN_ATTRIBUTES" => "false",
         | 
| 204 | 
            +
                  )
         | 
| 205 | 
            +
                  create_app(
         | 
| 206 | 
            +
                    "sp",
         | 
| 207 | 
            +
                    "ATTRIBUTE_MAP_RESOLVER" => "AttributeMapResolver",
         | 
| 208 | 
            +
                    "USE_SUBJECT_TO_AUTHENTICATE" => "true",
         | 
| 209 | 
            +
                  )
         | 
| 210 | 
            +
                  @idp_pid = start_app("idp", idp_port)
         | 
| 211 | 
            +
                  @sp_pid  = start_app("sp", sp_port)
         | 
| 212 | 
            +
                end
         | 
| 213 | 
            +
                after(:each) do
         | 
| 214 | 
            +
                  stop_app("idp", @idp_pid)
         | 
| 215 | 
            +
                  stop_app("sp", @sp_pid)
         | 
| 216 | 
            +
                end
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                it_behaves_like "it authenticates and creates users"
         | 
| 219 | 
            +
              end
         | 
| 220 | 
            +
             | 
| 196 221 | 
             
              def create_user(email)
         | 
| 197 222 | 
             
                response = Net::HTTP.post_form(URI('http://localhost:8020/users'), email: email)
         | 
| 198 223 | 
             
                expect(response.code).to eq('201')
         | 
| 199 224 | 
             
              end
         | 
| 200 225 |  | 
| 201 | 
            -
              def sign_in
         | 
| 202 | 
            -
                visit  | 
| 203 | 
            -
                expect(current_url).to match(%r(\Ahttp://localhost:8009/saml/auth\?SAMLRequest=))
         | 
| 226 | 
            +
              def sign_in(entity_id: "")
         | 
| 227 | 
            +
                visit "http://localhost:8020/users/saml/sign_in/?entity_id=#{URI.escape(entity_id)}"
         | 
| 204 228 | 
             
                fill_in "Email", with: "you@example.com"
         | 
| 205 229 | 
             
                fill_in "Password", with: "asdf"
         | 
| 206 230 | 
             
                click_on "Sign in"
         | 
| 207 | 
            -
                Timeout.timeout(Capybara. | 
| 231 | 
            +
                Timeout.timeout(Capybara.default_max_wait_time) do
         | 
| 208 232 | 
             
                  loop do
         | 
| 209 233 | 
             
                    sleep 0.1
         | 
| 210 234 | 
             
                    break if current_url == "http://localhost:8020/"
         | 
    
        data/spec/rails_helper.rb
    CHANGED
    
    | @@ -3,12 +3,16 @@ ENV["RAILS_ENV"] ||= 'test' | |
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 4 |  | 
| 5 5 | 
             
            create_app('sp', 'USE_SUBJECT_TO_AUTHENTICATE' => "false")
         | 
| 6 | 
            -
            require  | 
| 6 | 
            +
            require "#{working_directory}/sp/config/environment"
         | 
| 7 7 | 
             
            require 'rspec/rails'
         | 
| 8 8 |  | 
| 9 9 | 
             
            ActiveRecord::Migration.verbose = false
         | 
| 10 10 | 
             
            ActiveRecord::Base.logger = Logger.new(nil)
         | 
| 11 | 
            -
            ActiveRecord:: | 
| 11 | 
            +
            if ActiveRecord::Base.connection.respond_to?(:migration_context)
         | 
| 12 | 
            +
              ActiveRecord::Base.connection.migration_context.migrate
         | 
| 13 | 
            +
            else
         | 
| 14 | 
            +
              ActiveRecord::Migrator.migrate("#{working_directory}/sp/db/migrate/")
         | 
| 15 | 
            +
            end
         | 
| 12 16 |  | 
| 13 17 | 
             
            RSpec.configure do |config|
         | 
| 14 18 | 
             
              config.use_transactional_fixtures = true
         | 
| @@ -0,0 +1,102 @@ | |
| 1 | 
            +
            require 'rails_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe 'SamlAuthenticatable Routes', type: :routing do
         | 
| 4 | 
            +
              describe 'GET /users/saml/sign_in (login)' do
         | 
| 5 | 
            +
                it 'routes to Devise::SamlSessionsController#new' do
         | 
| 6 | 
            +
                  expect(get: '/users/saml/sign_in').to route_to(controller: 'devise/saml_sessions', action: 'new')
         | 
| 7 | 
            +
                  expect(get: new_user_session_path).to route_to(controller: 'devise/saml_sessions', action: 'new')
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              describe 'POST /users/saml/auth (session creation)' do
         | 
| 12 | 
            +
                it 'routes to Devise::SamlSessionsController#create' do
         | 
| 13 | 
            +
                  expect(post: '/users/saml/auth').to route_to(controller: 'devise/saml_sessions', action: 'create')
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              describe 'DELETE /users/sign_out (logout)' do
         | 
| 18 | 
            +
                it 'routes to Devise::SamlSessionsController#destroy' do
         | 
| 19 | 
            +
                  expect(delete: '/users/sign_out').to route_to(controller: 'devise/saml_sessions', action: 'destroy')
         | 
| 20 | 
            +
                  expect(delete: destroy_user_session_path).to route_to(controller: 'devise/saml_sessions', action: 'destroy')
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              describe 'GET /users/saml/metadata' do
         | 
| 25 | 
            +
                it 'routes to Devise::SamlSessionsController#metadata' do
         | 
| 26 | 
            +
                  expect(get: '/users/saml/metadata').to route_to(controller: 'devise/saml_sessions', action: 'metadata')
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              describe 'GET /users/saml/idp_sign_out (IdP-initiated logout)' do
         | 
| 31 | 
            +
                it 'routes to Devise::SamlSessionsController#idp_sign_out' do
         | 
| 32 | 
            +
                  expect(get: '/users/saml/idp_sign_out').to route_to(controller: 'devise/saml_sessions', action: 'idp_sign_out')
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              describe 'POST /users/saml/idp_sign_out (IdP-initiated logout)' do
         | 
| 37 | 
            +
                it 'routes to Devise::SamlSessionsController#idp_sign_out' do
         | 
| 38 | 
            +
                  expect(post: '/users/saml/idp_sign_out').to route_to(controller: 'devise/saml_sessions', action: 'idp_sign_out')
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              context 'when saml_route_helper_prefix is "sso"' do
         | 
| 43 | 
            +
                before(:all) do
         | 
| 44 | 
            +
                  ::Devise.saml_route_helper_prefix = 'sso'
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  # A very simple Rails engine
         | 
| 47 | 
            +
                  module SamlRouteHelperPrefixEngine
         | 
| 48 | 
            +
                    class Engine < ::Rails::Engine
         | 
| 49 | 
            +
                      isolate_namespace SamlRouteHelperPrefixEngine
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    Engine.routes.draw do
         | 
| 53 | 
            +
                      devise_for :users, module: :devise
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
                after(:all) do
         | 
| 58 | 
            +
                  ::Devise.saml_route_helper_prefix = nil
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
                routes { SamlRouteHelperPrefixEngine::Engine.routes }
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                describe 'GET /users/saml/sign_in (login)' do
         | 
| 63 | 
            +
                  it 'routes to Devise::SamlSessionsController#new' do
         | 
| 64 | 
            +
                    expect(get: '/users/saml/sign_in').to route_to(controller: 'devise/saml_sessions', action: 'new')
         | 
| 65 | 
            +
                    expect(get: new_sso_user_session_path).to route_to(controller: 'devise/saml_sessions', action: 'new')
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                describe 'POST /users/saml/auth (session creation)' do
         | 
| 70 | 
            +
                  it 'routes to Devise::SamlSessionsController#create' do
         | 
| 71 | 
            +
                    expect(post: '/users/saml/auth').to route_to(controller: 'devise/saml_sessions', action: 'create')
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                describe 'DELETE /users/sign_out (logout)' do
         | 
| 76 | 
            +
                  it 'routes to Devise::SamlSessionsController#destroy' do
         | 
| 77 | 
            +
                    expect(delete: '/users/sign_out').to route_to(controller: 'devise/saml_sessions', action: 'destroy')
         | 
| 78 | 
            +
                    expect(delete: destroy_sso_user_session_path).to route_to(controller: 'devise/saml_sessions', action: 'destroy')
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                describe 'GET /users/saml/metadata' do
         | 
| 83 | 
            +
                  it 'routes to Devise::SamlSessionsController#metadata' do
         | 
| 84 | 
            +
                    expect(get: '/users/saml/metadata').to route_to(controller: 'devise/saml_sessions', action: 'metadata')
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                describe 'GET /users/saml/idp_sign_out (IdP-initiated logout)' do
         | 
| 89 | 
            +
                  it 'routes to Devise::SamlSessionsController#idp_sign_out' do
         | 
| 90 | 
            +
                    expect(get: '/users/saml/idp_sign_out').to route_to(controller: 'devise/saml_sessions', action: 'idp_sign_out')
         | 
| 91 | 
            +
                    expect(get: idp_destroy_sso_user_session_path).to route_to(controller: 'devise/saml_sessions', action: 'idp_sign_out')
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                describe 'POST /users/saml/idp_sign_out (IdP-initiated logout)' do
         | 
| 96 | 
            +
                  it 'routes to Devise::SamlSessionsController#idp_sign_out' do
         | 
| 97 | 
            +
                    expect(post: '/users/saml/idp_sign_out').to route_to(controller: 'devise/saml_sessions', action: 'idp_sign_out')
         | 
| 98 | 
            +
                    expect(post: idp_destroy_sso_user_session_path).to route_to(controller: 'devise/saml_sessions', action: 'idp_sign_out')
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require "fileutils"
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            RSpec.configure do |config|
         | 
| 2 4 | 
             
              config.run_all_when_everything_filtered = true
         | 
| 3 5 | 
             
              config.filter_run :focus
         | 
| @@ -28,8 +30,13 @@ RSpec.configure do |config| | |
| 28 30 | 
             
                Devise.saml_session_index_key = @original_saml_session_index_key
         | 
| 29 31 | 
             
                Devise.idp_settings_adapter = nil
         | 
| 30 32 | 
             
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              config.after :suite do
         | 
| 35 | 
            +
                FileUtils.rm_rf($working_directory) if $working_directory
         | 
| 36 | 
            +
              end
         | 
| 31 37 | 
             
            end
         | 
| 32 38 |  | 
| 33 39 | 
             
            require 'support/rails_app'
         | 
| 34 40 |  | 
| 41 | 
            +
            require "action_controller" # https://github.com/heartcombo/responders/pull/95
         | 
| 35 42 | 
             
            require 'devise_saml_authenticatable'
         |