devise_saml_authenticatable 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 377131d065bd2670e5830eff8c0cdf75fa221d69
4
- data.tar.gz: 9304fbf24d72a198ea36290fe45f25a63be62790
3
+ metadata.gz: 388799cd1bf9c14ad21b7a042d63957d965ec080
4
+ data.tar.gz: b5e153ee444879be849e6ddda43e2762a3905092
5
5
  SHA512:
6
- metadata.gz: 0d4d5fb0973e73ee61052e9ba5f2a34cc5bf721659e32d0b760db46d355648cd1d825e7510278e73f7597aa4fb52c87187270441131bf409baf1308583ccfeb7
7
- data.tar.gz: 0749346b7c5d0db06780fe811763eb62ffebb49f0f0d0c5d6de45c69fd04baafb3fd3c8957c95628c403044bfc26b2ee27460db28817c05d3ca5802d58b3842d
6
+ metadata.gz: 2c304efa473b057a46895b96db3d6d076ebdaa332de7c7d6a3480b86a3ae3e33d17123b5f565d229c5412a9496cc9c549e34960aa119f8a1c18180eea87eb05e
7
+ data.tar.gz: 40a2dd033fd20cccc2803dc587309be272005a5d84c8e80a0325b038079fcd2deb9b6aad78f8afb30c2462f9952efe1e49ffa100b9187480c5234a6565aaf566
@@ -3,12 +3,14 @@ rvm:
3
3
  - "1.9.3"
4
4
  - "2.0.0"
5
5
  - "2.1.10"
6
- - "2.2.9"
7
- - "2.3.6"
8
- - "2.4.3"
9
- - "2.5.0"
6
+ - "2.2.10"
7
+ - "2.3.8"
8
+ - "2.4.5"
9
+ - "2.5.3"
10
+ - "2.6.0"
10
11
  gemfile:
11
12
  - Gemfile
13
+ - spec/support/Gemfile.rails5.1
12
14
  - spec/support/Gemfile.rails5
13
15
  - spec/support/Gemfile.rails4
14
16
  matrix:
@@ -17,18 +19,26 @@ matrix:
17
19
  gemfile: Gemfile
18
20
  - rvm: "1.9.3"
19
21
  gemfile: spec/support/Gemfile.rails5
22
+ - rvm: "1.9.3"
23
+ gemfile: spec/support/Gemfile.rails5.1
20
24
  - rvm: "2.0.0"
21
25
  gemfile: Gemfile
22
26
  - rvm: "2.0.0"
23
27
  gemfile: spec/support/Gemfile.rails5
28
+ - rvm: "2.0.0"
29
+ gemfile: spec/support/Gemfile.rails5.1
24
30
  - rvm: "2.1.10"
25
31
  gemfile: Gemfile
26
32
  - rvm: "2.1.10"
27
33
  gemfile: spec/support/Gemfile.rails5
34
+ - rvm: "2.1.10"
35
+ gemfile: spec/support/Gemfile.rails5.1
36
+ - rvm: "2.6.0"
37
+ gemfile: spec/support/Gemfile.rails4
28
38
 
29
39
  before_install:
30
40
  # update bundler to avoid https://github.com/travis-ci/travis-ci/issues/5239
31
- - gem install bundler
41
+ - command -v bundle || gem install bundler -v '~> 1.17.3'
32
42
 
33
43
  script:
34
44
  - bundle exec rake
data/README.md CHANGED
@@ -20,6 +20,10 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ Follow the [normal devise installation process](https://github.com/plataformatec/devise/tree/master#getting-started). The controller filters and helpers are unchanged from normal devise usage.
24
+
25
+ ### Configuring Models
26
+
23
27
  In `app/models/<YOUR_MODEL>.rb` set the `:saml_authenticatable` strategy.
24
28
 
25
29
  In the example the model is `user.rb`:
@@ -32,6 +36,37 @@ In the example the model is `user.rb`:
32
36
  end
33
37
  ```
34
38
 
39
+ ### Configuring routes
40
+
41
+ In `config/routes.rb` add `devise_for` to set up helper methods and routes:
42
+
43
+ ```ruby
44
+ devise_for :users
45
+ ```
46
+
47
+ The named routes can be customized in the initializer config file.
48
+
49
+ ### Configuring the IdP
50
+
51
+ An extra step in SAML SSO setup is adding your application to your identity provider. The required setup is specific to each IdP, but we have some examples in [our wiki](https://github.com/apokalipto/devise_saml_authenticatable/wiki). You'll need to tell your IdP how to send requests and responses to your application.
52
+
53
+ - Creating a new session: `/users/saml/auth`
54
+ - IdPs may call this the "consumer," "recipient," "destination," or even "single sign-on." This is where they send a SAML response for an authenticated user.
55
+ - Metadata: `/users/saml/metadata`
56
+ - IdPs may call this the "audience."
57
+ - Single Logout: `/users/saml/idp_sign_out`
58
+ - if desired, you can ask the IdP to send a Logout request to this endpoint to sign the user out of your application when they sign out of the IdP itself.
59
+
60
+ Your IdP should give you some information you need to configure in [ruby-saml](https://github.com/onelogin/ruby-saml), as in the next section:
61
+
62
+ - Issuer (`idp_entity_id`)
63
+ - SSO endpoint (`idp_sso_target_url`)
64
+ - SLO endpoint (`idp_slo_target_url`)
65
+ - Certificate fingerprint (`idp_cert_fingerprint`) and algorithm (`idp_cert_fingerprint_algorithm`)
66
+ - Or the certificate itself (`idp_cert`)
67
+
68
+ ### Configuring handling of IdP requests and responses
69
+
35
70
  In `config/initializers/devise.rb`:
36
71
 
37
72
  ```ruby
@@ -69,6 +104,12 @@ In `config/initializers/devise.rb`:
69
104
  # and implements a #handle method. This method can then redirect the user, return error messages, etc.
70
105
  # config.saml_failed_callback = nil
71
106
 
107
+ # You can customize the named routes generated in case of named route collisions with
108
+ # other Devise modules or libraries. Set the saml_route_helper_prefix to a string that will
109
+ # be appended to the named route.
110
+ # If saml_route_helper_prefix = 'saml' then the new_user_session route becomes new_saml_user_session
111
+ # config.saml_route_helper_prefix = 'saml'
112
+
72
113
  # Configure with your SAML settings (see ruby-saml's README for more information: https://github.com/onelogin/ruby-saml).
73
114
  config.saml_configure do |settings|
74
115
  # assertion_consumer_service_url is required starting with ruby-saml 1.4.3: https://github.com/onelogin/ruby-saml#updating-from-142-to-143
@@ -79,24 +120,8 @@ In `config/initializers/devise.rb`:
79
120
  settings.authn_context = ""
80
121
  settings.idp_slo_target_url = "http://localhost/simplesaml/www/saml2/idp/SingleLogoutService.php"
81
122
  settings.idp_sso_target_url = "http://localhost/simplesaml/www/saml2/idp/SSOService.php"
82
- settings.idp_cert = <<-CERT.chomp
83
- -----BEGIN CERTIFICATE-----
84
- 1111111111111111111111111111111111111111111111111111111111111111
85
- 1111111111111111111111111111111111111111111111111111111111111111
86
- 1111111111111111111111111111111111111111111111111111111111111111
87
- 1111111111111111111111111111111111111111111111111111111111111111
88
- 1111111111111111111111111111111111111111111111111111111111111111
89
- 1111111111111_______IDP_CERTIFICATE________111111111111111111111
90
- 1111111111111111111111111111111111111111111111111111111111111111
91
- 1111111111111111111111111111111111111111111111111111111111111111
92
- 1111111111111111111111111111111111111111111111111111111111111111
93
- 1111111111111111111111111111111111111111111111111111111111111111
94
- 1111111111111111111111111111111111111111111111111111111111111111
95
- 1111111111111111111111111111111111111111111111111111111111111111
96
- 1111111111111111111111111111111111111111111111111111111111111111
97
- 111111111111111111
98
- -----END CERTIFICATE-----
99
- CERT
123
+ settings.idp_cert_fingerprint = "00:A1:2B:3C:44:55:6F:A7:88:CC:DD:EE:22:33:44:55:D6:77:8F:99"
124
+ settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
100
125
  end
101
126
  end
102
127
  ```
@@ -19,6 +19,10 @@ end
19
19
 
20
20
  # Get saml information from config/saml.yml now
21
21
  module Devise
22
+ # Allow route customization to avoid collision
23
+ mattr_accessor :saml_route_helper_prefix
24
+ @@saml_route_helper_prefix
25
+
22
26
  # Allow logging
23
27
  mattr_accessor :saml_logger
24
28
  @@saml_logger = true
@@ -64,9 +68,17 @@ module Devise
64
68
 
65
69
  # Implements a #validate method that takes the retrieved resource and response right after retrieval,
66
70
  # and returns true if it's valid. False will cause authentication to fail.
71
+ # Only one of saml_resource_validator and saml_resource_validator_hook may be used.
67
72
  mattr_accessor :saml_resource_validator
68
73
  @@saml_resource_validator
69
74
 
75
+ # Proc that determines whether a technically correct SAML response is valid per some custom logic.
76
+ # Receives the user object (or nil, if no match was found), decorated saml_response and
77
+ # auth_value, inspects the combination for acceptability of login (or create+login, if enabled),
78
+ # and returns true if it's valid. False will cause authentication to fail.
79
+ mattr_accessor :saml_resource_validator_hook
80
+ @@saml_resource_validator_hook
81
+
70
82
  # Custom value for ruby-saml allowed_clock_drift
71
83
  mattr_accessor :allowed_clock_drift_in_seconds
72
84
  @@allowed_clock_drift_in_seconds
@@ -44,8 +44,12 @@ module Devise
44
44
 
45
45
  resource = Devise.saml_resource_locator.call(self, decorated_response, auth_value)
46
46
 
47
- if Devise.saml_resource_validator
48
- if not Devise.saml_resource_validator.new.validate(resource, saml_response)
47
+ raise "Only one validator configuration can be used at a time" if Devise.saml_resource_validator && Devise.saml_resource_validator_hook
48
+ if Devise.saml_resource_validator || Devise.saml_resource_validator_hook
49
+ valid = if Devise.saml_resource_validator then Devise.saml_resource_validator.new.validate(resource, saml_response)
50
+ else Devise.saml_resource_validator_hook.call(resource, decorated_response, auth_value)
51
+ end
52
+ if !valid
49
53
  logger.info("User(#{auth_value}) did not pass custom validation.")
50
54
  return nil
51
55
  end
@@ -1,12 +1,23 @@
1
1
  ActionDispatch::Routing::Mapper.class_eval do
2
2
  protected
3
3
  def devise_saml_authenticatable(mapping, controllers)
4
- resource :session, :only => [], :controller => controllers[:saml_sessions], :path => "" do
5
- get :new, :path => "saml/sign_in", :as => "new"
6
- post :create, :path=>"saml/auth"
7
- match :destroy, :path => mapping.path_names[:sign_out], :as => "destroy", :via => mapping.sign_out_via
8
- get :metadata, :path=>"saml/metadata"
9
- match :idp_sign_out, :path=>"saml/idp_sign_out", via: [:get, :post]
4
+ if ::Devise.saml_route_helper_prefix
5
+ prefix = ::Devise.saml_route_helper_prefix
6
+ resource :session, only: [], controller: controllers[:saml_sessions], path: '' do
7
+ get :new, path: 'saml/sign_in', as: "new_#{prefix}"
8
+ post :create, path: 'saml/auth', as: prefix
9
+ match :destroy, path: mapping.path_names[:sign_out], as: "destroy_#{prefix}", via: mapping.sign_out_via
10
+ get :metadata, path: 'saml/metadata'
11
+ match :idp_sign_out, path: 'saml/idp_sign_out', as: "idp_destroy_#{prefix}", via: [:get, :post]
12
+ end
13
+ else
14
+ resource :session, only: [], controller: controllers[:saml_sessions], path: '' do
15
+ get :new, path: 'saml/sign_in', as: 'new'
16
+ post :create, path: 'saml/auth'
17
+ match :destroy, path: mapping.path_names[:sign_out], as: 'destroy', via: mapping.sign_out_via
18
+ get :metadata, path: 'saml/metadata'
19
+ match :idp_sign_out, path: 'saml/idp_sign_out', via: [:get, :post]
20
+ end
10
21
  end
11
22
  end
12
23
  end
@@ -3,7 +3,6 @@ module SamlAuthenticatable
3
3
  def initialize(attributes, attribute_map)
4
4
  @attributes = attributes
5
5
  @attribute_map = attribute_map
6
- @inverted_attribute_map = @attribute_map.invert
7
6
  end
8
7
 
9
8
  def saml_attribute_keys
@@ -15,7 +14,21 @@ module SamlAuthenticatable
15
14
  end
16
15
 
17
16
  def value_by_resource_key(key)
18
- value_by_saml_attribute_key(@inverted_attribute_map.fetch(String(key)))
17
+ str_key = String(key)
18
+
19
+ # Find all of the SAML attributes that map to the resource key
20
+ attribute_map_for_key = @attribute_map.select { |_, resource_key| String(resource_key) == str_key }
21
+
22
+ saml_value = nil
23
+
24
+ # Find the first non-nil value
25
+ attribute_map_for_key.each_key do |saml_key|
26
+ saml_value = value_by_saml_attribute_key(saml_key)
27
+
28
+ break unless saml_value.nil?
29
+ end
30
+
31
+ saml_value
19
32
  end
20
33
 
21
34
  def value_by_saml_attribute_key(key)
@@ -1,3 +1,3 @@
1
1
  module DeviseSamlAuthenticatable
2
- VERSION = "1.4.1"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -39,13 +39,15 @@ describe Devise::Models::SamlAuthenticatable do
39
39
 
40
40
  before do
41
41
  allow(Rails).to receive(:root).and_return("/railsroot")
42
- allow(File).to receive(:read).with("/railsroot/config/attribute-map.yml").and_return(<<-ATTRIBUTEMAP)
42
+ allow(File).to receive(:read).with("/railsroot/config/attribute-map.yml").and_return(attributemap)
43
+ end
44
+
45
+ let(:attributemap) {<<-ATTRIBUTEMAP
43
46
  ---
44
47
  "saml-email-format": email
45
48
  "saml-name-format": name
46
49
  ATTRIBUTEMAP
47
- end
48
-
50
+ }
49
51
  let(:response) { double(:response, attributes: attributes, name_id: name_id) }
50
52
  let(:attributes) {
51
53
  OneLogin::RubySaml::Attributes.new(
@@ -179,8 +181,8 @@ describe Devise::Models::SamlAuthenticatable do
179
181
  end
180
182
  end
181
183
 
182
- context "when configured with a resource validator" do
183
- let(:validator_class) { double("validator_class") }
184
+ context "when configured with a resource validator class" do
185
+ let(:validator_class) { double("validator") }
184
186
  let(:validator) { double("validator") }
185
187
  let(:user) { Model.new(new_record: false) }
186
188
 
@@ -212,6 +214,41 @@ describe Devise::Models::SamlAuthenticatable do
212
214
  end
213
215
  end
214
216
 
217
+
218
+ context "when configured with a resource validator hook" do
219
+ let(:validator_hook) { double("validator_hook") }
220
+ let(:decorated_response) { ::SamlAuthenticatable::SamlResponse.new(response, YAML.load(attributemap)) }
221
+ let(:user) { Model.new(new_record: false) }
222
+
223
+ before do
224
+ allow(Devise).to receive(:saml_resource_validator_hook).and_return(validator_hook)
225
+ allow(::SamlAuthenticatable::SamlResponse).to receive(:new).with(response, YAML.load(attributemap)).and_return(decorated_response)
226
+ end
227
+
228
+ context "and sent a valid value" do
229
+ before do
230
+ expect(validator_hook).to receive(:call).with(user, decorated_response, 'user@example.com').and_return(true)
231
+ end
232
+
233
+ it "returns the user" do
234
+ expect(Model).to receive(:where).with(email: 'user@example.com').and_return([user])
235
+ expect(Model.authenticate_with_saml(response, nil)).to eq(user)
236
+ end
237
+ end
238
+
239
+ context "and sent an invalid value" do
240
+ before do
241
+ expect(validator_hook).to receive(:call).with(user, decorated_response, 'user@example.com').and_return(false)
242
+ end
243
+
244
+ it "returns nil" do
245
+ expect(Model).to receive(:where).with(email: 'user@example.com').and_return([user])
246
+ expect(Model.authenticate_with_saml(response, nil)).to be_nil
247
+ end
248
+ end
249
+ end
250
+
251
+
215
252
  context "when configured to use a custom update hook" do
216
253
  it "can replicate the default behaviour in a custom hook" do
217
254
  configure_hook do |user, saml_response|
@@ -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 }
@@ -203,7 +204,7 @@ describe "SAML Authentication", type: :feature do
203
204
  fill_in "Email", with: "you@example.com"
204
205
  fill_in "Password", with: "asdf"
205
206
  click_on "Sign in"
206
- expect(page).to have_content("Example Domain This domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission.")
207
+ expect(page).to have_content(:all, "Example Domain This domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission.")
207
208
  expect(current_url).to eq("http://www.example.com/")
208
209
  end
209
210
  end
@@ -220,7 +221,7 @@ describe "SAML Authentication", type: :feature do
220
221
  fill_in "Email", with: "you@example.com"
221
222
  fill_in "Password", with: "asdf"
222
223
  click_on "Sign in"
223
- Timeout.timeout(Capybara.default_wait_time) do
224
+ Timeout.timeout(Capybara.default_max_wait_time) do
224
225
  loop do
225
226
  sleep 0.1
226
227
  break if current_url == "http://localhost:8020/"
@@ -8,7 +8,11 @@ require 'rspec/rails'
8
8
 
9
9
  ActiveRecord::Migration.verbose = false
10
10
  ActiveRecord::Base.logger = Logger.new(nil)
11
- ActiveRecord::Migrator.migrate(File.expand_path("../support/sp/db/migrate/", __FILE__))
11
+ if ActiveRecord::Base.connection.respond_to?(:migration_context)
12
+ ActiveRecord::Base.connection.migration_context.migrate
13
+ else
14
+ ActiveRecord::Migrator.migrate(File.expand_path("../support/sp/db/migrate/", __FILE__))
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
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in devise_saml_authenticatable.gemspec
4
+ gemspec path: '../..'
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ gem 'rspec', '~> 3.0'
9
+ gem 'rails', '~> 5.1.0'
10
+ gem 'rspec-rails'
11
+ gem 'sqlite3'
12
+ gem 'capybara'
13
+ gem 'poltergeist'
14
+ end
@@ -0,0 +1,12 @@
1
+ "urn:mace:dir:attribute-def:first_name": "first_name"
2
+ "first_name": "first_name"
3
+ "firstName": "first_name"
4
+ "firstname": "first_name"
5
+ "urn:mace:dir:attribute-def:last_name": "last_name"
6
+ "last_name": "last_name"
7
+ "lastName": "last_name"
8
+ "lastname": "last_name"
9
+ "urn:mace:dir:attribute-def:email": "email"
10
+ "email_address": "email"
11
+ "emailAddress": "email"
12
+ "email": "email"
@@ -3,7 +3,9 @@
3
3
  @include_subject_in_attributes = ENV.fetch('INCLUDE_SUBJECT_IN_ATTRIBUTES')
4
4
  @valid_destination = ENV.fetch('VALID_DESTINATION', "true")
5
5
 
6
- gsub_file 'config/secrets.yml', /secret_key_base:.*$/, 'secret_key_base: "34814fd41f91c493b89aa01ac73c44d241a31245b5bc5542fa4b7317525e1dcfa60ba947b3d085e4e229456fdee0d8af6aac6a63cf750d807ea6fe5d853dff4a"'
6
+ if Rails::VERSION::MAJOR < 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR < 2)
7
+ gsub_file 'config/secrets.yml', /secret_key_base:.*$/, 'secret_key_base: "34814fd41f91c493b89aa01ac73c44d241a31245b5bc5542fa4b7317525e1dcfa60ba947b3d085e4e229456fdee0d8af6aac6a63cf750d807ea6fe5d853dff4a"'
8
+ end
7
9
 
8
10
  gem 'ruby-saml-idp', git: "https://github.com/lawrencepit/ruby-saml-idp.git", ref: "ec715b252e849105c7a96df27b731c6e7f725a51"
9
11
  gem 'thin'
@@ -17,7 +17,7 @@ rescue Errno::ESRCH
17
17
  end
18
18
 
19
19
  def create_app(name, env = {})
20
- rails_new_options = %w(-T -J -S --skip-spring --skip-listen)
20
+ rails_new_options = %w(-T -J -S --skip-spring --skip-listen --skip-bootsnap)
21
21
  rails_new_options << "-O" if name == 'idp'
22
22
  Dir.chdir(File.expand_path('../../support', __FILE__)) do
23
23
  FileUtils.rm_rf(name)
@@ -8,7 +8,9 @@ idp_settings_adapter = ENV.fetch('IDP_SETTINGS_ADAPTER', "nil")
8
8
  idp_entity_id_reader = ENV.fetch('IDP_ENTITY_ID_READER', "DeviseSamlAuthenticatable::DefaultIdpEntityIdReader")
9
9
  saml_failed_callback = ENV.fetch('SAML_FAILED_CALLBACK', "nil")
10
10
 
11
- gsub_file 'config/secrets.yml', /secret_key_base:.*$/, 'secret_key_base: "8b5889df1fcf03f76c7d66da02d8776bcc85b06bed7d9c592f076d9c8a5455ee6d4beae45986c3c030b40208db5e612f2a6ef8283036a352e3fae83c5eda36be"'
11
+ if Rails::VERSION::MAJOR < 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR < 2)
12
+ gsub_file 'config/secrets.yml', /secret_key_base:.*$/, 'secret_key_base: "8b5889df1fcf03f76c7d66da02d8776bcc85b06bed7d9c592f076d9c8a5455ee6d4beae45986c3c030b40208db5e612f2a6ef8283036a352e3fae83c5eda36be"'
13
+ end
12
14
 
13
15
  gem 'devise_saml_authenticatable', path: '../../..'
14
16
  gem 'ruby-saml', OneLogin::RubySaml::VERSION
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise_saml_authenticatable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josef Sauter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-08 00:00:00.000000000 Z
11
+ date: 2019-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: devise
@@ -70,12 +70,16 @@ files:
70
70
  - spec/devise_saml_authenticatable/default_idp_entity_id_reader_spec.rb
71
71
  - spec/devise_saml_authenticatable/model_spec.rb
72
72
  - spec/devise_saml_authenticatable/saml_config_spec.rb
73
+ - spec/devise_saml_authenticatable/saml_mapped_attributes_spec.rb
73
74
  - spec/devise_saml_authenticatable/strategy_spec.rb
74
75
  - spec/features/saml_authentication_spec.rb
75
76
  - spec/rails_helper.rb
77
+ - spec/routes/routes_spec.rb
76
78
  - spec/spec_helper.rb
77
79
  - spec/support/Gemfile.rails4
78
80
  - spec/support/Gemfile.rails5
81
+ - spec/support/Gemfile.rails5.1
82
+ - spec/support/attribute-map.yml
79
83
  - spec/support/idp_settings_adapter.rb.erb
80
84
  - spec/support/idp_template.rb
81
85
  - spec/support/rails_app.rb
@@ -112,12 +116,16 @@ test_files:
112
116
  - spec/devise_saml_authenticatable/default_idp_entity_id_reader_spec.rb
113
117
  - spec/devise_saml_authenticatable/model_spec.rb
114
118
  - spec/devise_saml_authenticatable/saml_config_spec.rb
119
+ - spec/devise_saml_authenticatable/saml_mapped_attributes_spec.rb
115
120
  - spec/devise_saml_authenticatable/strategy_spec.rb
116
121
  - spec/features/saml_authentication_spec.rb
117
122
  - spec/rails_helper.rb
123
+ - spec/routes/routes_spec.rb
118
124
  - spec/spec_helper.rb
119
125
  - spec/support/Gemfile.rails4
120
126
  - spec/support/Gemfile.rails5
127
+ - spec/support/Gemfile.rails5.1
128
+ - spec/support/attribute-map.yml
121
129
  - spec/support/idp_settings_adapter.rb.erb
122
130
  - spec/support/idp_template.rb
123
131
  - spec/support/rails_app.rb