devise_saml_authenticatable 1.6.3 → 1.9.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f648472eaaf23e5e668e51f84fadff2354879045f0ec798a383dd8a2e2ee135a
4
- data.tar.gz: 443a5e883595f8baa2297e2ca173e8f97ae0abf3502538ce1d0f4e0e1c84081e
3
+ metadata.gz: f5dd2cc3931480caf617a4a22266968ea550c52c4980353a5e295652dc25ce4d
4
+ data.tar.gz: b712dd20efd0c4ddd9c8a1321dc6e2cbf8876053689c36c94d272be5445f8fd7
5
5
  SHA512:
6
- metadata.gz: 4765fe0a60d2a8ffd97d30d5b0d2fdb55d70a56bd9cb91f760ef7862a0d9ec80570da5d4758a784ac552232e1e5893fdd1accead2ff677893b0eb4a3500dcb9c
7
- data.tar.gz: fcd0e6f70b75fdb9b12b3c1954899989e26f8ddb874c6222ab59ca460387a9672ab7767c13855bc4c3cbabd14fdcdb3ddabb2478412dbb452a17194c20ff4c32
6
+ metadata.gz: 697615b8dfb2f798ae0fd71b796359825633b783fbebaf66cc947bd33d78ded081a862609b55b6407d87495a7a3b3df4ae9dfce1dd2143d7ce54e2c811727d1e
7
+ data.tar.gz: 74037754bbe52f5036aed75ad1d96cd0a44677f2963f496a5986a8f6be0542f92645f6a3c8fa67e738a9656d2d9697566f41dfbe6f5aa4b8306114e99a182864
@@ -0,0 +1,52 @@
1
+ name: ci
2
+ on:
3
+ push:
4
+ branches:
5
+ - master
6
+ pull_request:
7
+ branches:
8
+ - master
9
+ jobs:
10
+ test:
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ ruby:
15
+ - "3.1"
16
+ - "3.0"
17
+ - "2.7"
18
+ - "2.6"
19
+ gemfile:
20
+ - Gemfile
21
+ - spec/support/Gemfile.rails6.1
22
+ - spec/support/Gemfile.rails6
23
+ - spec/support/Gemfile.rails5.2
24
+ bundler:
25
+ - "2"
26
+ exclude:
27
+ - ruby: "2.6"
28
+ gemfile: Gemfile
29
+ bundler: "2"
30
+ - ruby: "3.0"
31
+ gemfile: spec/support/Gemfile.rails5.2
32
+ bundler: "2"
33
+ - ruby: "3.0"
34
+ gemfile: spec/support/Gemfile.rails6
35
+ bundler: "2"
36
+ - ruby: "3.1"
37
+ gemfile: spec/support/Gemfile.rails5.2
38
+ bundler: "2"
39
+ - ruby: "3.1"
40
+ gemfile: spec/support/Gemfile.rails6
41
+ bundler: "2"
42
+ runs-on: ubuntu-latest
43
+ env:
44
+ BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
45
+ steps:
46
+ - uses: actions/checkout@v2
47
+ - uses: ruby/setup-ruby@v1
48
+ with:
49
+ bundler: ${{ matrix.bundler }}
50
+ ruby-version: ${{ matrix.ruby }}
51
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
52
+ - run: bundle exec rake
data/.gitignore CHANGED
@@ -13,4 +13,5 @@ lib/bundler/man
13
13
  pkg
14
14
  rdoc
15
15
  spec/reports
16
+ spec/support/bin/*
16
17
  tmp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.0
data/Gemfile CHANGED
@@ -6,9 +6,19 @@ gemspec
6
6
  group :test do
7
7
  gem 'rake'
8
8
  gem 'rspec', '~> 3.0'
9
- gem 'rails', '~> 6.0'
9
+ gem 'rails', '~> 7.0.0'
10
10
  gem 'rspec-rails'
11
11
  gem 'sqlite3', '~> 1.4.0'
12
12
  gem 'capybara'
13
- gem 'poltergeist'
13
+ gem 'selenium-webdriver'
14
+
15
+ if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new("3.0")
16
+ gem 'webrick'
17
+ end
18
+
19
+ if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new("3.1")
20
+ gem 'net-smtp', require: false
21
+ gem 'net-imap', require: false
22
+ gem 'net-pop', require: false
23
+ end
14
24
  end
data/README.md CHANGED
@@ -57,8 +57,8 @@ An extra step in SAML SSO setup is adding your application to your identity prov
57
57
  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:
58
58
 
59
59
  - Issuer (`idp_entity_id`)
60
- - SSO endpoint (`idp_sso_target_url`)
61
- - SLO endpoint (`idp_slo_target_url`)
60
+ - SSO endpoint (`idp_sso_service_url`)
61
+ - SLO endpoint (`idp_slo_service_url`)
62
62
  - Certificate fingerprint (`idp_cert_fingerprint`) and algorithm (`idp_cert_fingerprint_algorithm`)
63
63
  - Or the certificate itself (`idp_cert`)
64
64
 
@@ -72,11 +72,42 @@ In `config/initializers/devise.rb`:
72
72
  # ==> Configuration for :saml_authenticatable
73
73
 
74
74
  # Create user if the user does not exist. (Default is false)
75
+ # Can also accept a proc, for ex:
76
+ # Devise.saml_create_user = Proc.new do |model_class, saml_response, auth_value|
77
+ # model_class == Admin
78
+ # end
75
79
  config.saml_create_user = true
76
80
 
77
81
  # Update the attributes of the user after a successful login. (Default is false)
82
+ # Can also accept a proc, for ex:
83
+ # Devise.saml_update_user = Proc.new do |model_class, saml_response, auth_value|
84
+ # model_class == Admin
85
+ # end
78
86
  config.saml_update_user = true
79
87
 
88
+ # Lambda that is called if Devise.saml_update_user and/or Devise.saml_create_user are true.
89
+ # Receives the model object, saml_response and auth_value, and defines how the object's values are
90
+ # updated with regards to the SAML response.
91
+ # config.saml_update_resource_hook = -> (user, saml_response, auth_value) {
92
+ # saml_response.attributes.resource_keys.each do |key|
93
+ # user.send "#{key}=", saml_response.attribute_value_by_resource_key(key)
94
+ # end
95
+ #
96
+ # if (Devise.saml_use_subject)
97
+ # user.send "#{Devise.saml_default_user_key}=", auth_value
98
+ # end
99
+ #
100
+ # user.save!
101
+ # }
102
+
103
+ # Lambda that is called to resolve the saml_response and auth_value into the correct user object.
104
+ # Receives a copy of the ActiveRecord::Model, saml_response and auth_value. Is expected to return
105
+ # one instance of the provided model that is the matched account, or nil if none exists.
106
+ # config.saml_resource_locator = -> (model, saml_response, auth_value) {
107
+ # model.where(Devise.saml_default_user_key => auth_value).first
108
+ # }
109
+
110
+
80
111
  # Set the default user key. The user will be looked up by this key. Make
81
112
  # sure that the Authentication Response includes the attribute.
82
113
  config.saml_default_user_key = :email
@@ -85,21 +116,21 @@ In `config/initializers/devise.rb`:
85
116
  # for the user's session to facilitate an IDP initiated logout request.
86
117
  config.saml_session_index_key = :session_index
87
118
 
88
- # You can set this value to use Subject or SAML assertation as info to which email will be compared.
89
- # If you don't set it then email will be extracted from SAML assertation attributes.
119
+ # You can set this value to use Subject or SAML assertion as info to which email will be compared.
120
+ # If you don't set it then email will be extracted from SAML assertion attributes.
90
121
  config.saml_use_subject = true
91
122
 
92
- # You can support multiple IdPs by setting this value to the name of a class that implements a ::settings method
93
- # which takes an IdP entity id as an argument and returns a hash of idp settings for the corresponding IdP.
123
+ # You can implement IdP settings with the options to support multiple IdPs and use the request object by setting this value to the name of a class that implements a ::settings method
124
+ # which takes an IdP entity id and a request object as arguments and returns a hash of idp settings for the corresponding IdP.
94
125
  # config.idp_settings_adapter = "MyIdPSettingsAdapter"
95
126
 
96
127
  # You provide you own method to find the idp_entity_id in a SAML message in the case of multiple IdPs
97
128
  # by setting this to the name of a custom reader class, or use the default.
98
129
  # config.idp_entity_id_reader = "DeviseSamlAuthenticatable::DefaultIdpEntityIdReader"
99
130
 
100
- # You can set a handler object that takes the response for a failed SAML request and the strategy,
131
+ # You can set the name of a class that takes the response for a failed SAML request and the strategy,
101
132
  # and implements a #handle method. This method can then redirect the user, return error messages, etc.
102
- # config.saml_failed_callback = nil
133
+ # config.saml_failed_callback = "MySamlFailedCallbacksHandler"
103
134
 
104
135
  # You can customize the named routes generated in case of named route collisions with
105
136
  # other Devise modules or libraries. Set the saml_route_helper_prefix to a string that will
@@ -111,16 +142,19 @@ In `config/initializers/devise.rb`:
111
142
  # This is a time in seconds.
112
143
  # config.allowed_clock_drift_in_seconds = 0
113
144
 
145
+ # In SAML responses, validate that the identity provider has included an InResponseTo
146
+ # header that matches the ID of the SAML request. (Default is false)
147
+ # config.saml_validate_in_response_to = false
148
+
114
149
  # Configure with your SAML settings (see ruby-saml's README for more information: https://github.com/onelogin/ruby-saml).
115
150
  config.saml_configure do |settings|
116
- # assertion_consumer_service_url is required starting with ruby-saml 1.4.3: https://github.com/onelogin/ruby-saml#updating-from-142-to-143
117
151
  settings.assertion_consumer_service_url = "http://localhost:3000/users/saml/auth"
118
152
  settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
119
153
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
120
154
  settings.issuer = "http://localhost:3000/saml/metadata"
121
155
  settings.authn_context = ""
122
- settings.idp_slo_target_url = "http://localhost/simplesaml/www/saml2/idp/SingleLogoutService.php"
123
- settings.idp_sso_target_url = "http://localhost/simplesaml/www/saml2/idp/SSOService.php"
156
+ settings.idp_slo_service_url = "http://localhost/simplesaml/www/saml2/idp/SingleLogoutService.php"
157
+ settings.idp_sso_service_url = "http://localhost/simplesaml/www/saml2/idp/SSOService.php"
124
158
  settings.idp_cert_fingerprint = "00:A1:2B:3C:44:55:6F:A7:88:CC:DD:EE:22:33:44:55:D6:77:8F:99"
125
159
  settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
126
160
  end
@@ -191,24 +225,26 @@ If you only have one IdP, you can use the config file above, or just return a si
191
225
  end
192
226
  ```
193
227
 
194
- ## Supporting Multiple IdPs
228
+ ## IdP Settings Adapter
229
+
230
+ Implementing a custom settings adapter allows you to support multiple Identity Providers, and dynamic application domains with the request object.
195
231
 
196
- If you must support multiple Identity Providers you can implement an adapter class with a `#settings` method that takes an IdP entity id and returns a hash of settings for the corresponding IdP. The `config.idp_settings_adapter` then must be set to point to your adapter in `config/initializers/devise.rb`. The implementation of the adapter is up to you. A simple example may look like this:
232
+ You can implement an adapter class with a `#settings` method. It must take two arguments (idp_entity_id, request) and return a hash of settings for the corresponding IdP. The `config.idp_settings_adapter` then must be set to point to your adapter in `config/initializers/devise.rb`. The implementation of the adapter is up to you. A simple example may look like this:
197
233
 
198
234
  ```ruby
199
235
  class IdPSettingsAdapter
200
- def self.settings(idp_entity_id)
236
+ def self.settings(idp_entity_id, request)
201
237
  case idp_entity_id
202
238
  when "http://www.example_idp_entity_id.com"
203
239
  {
204
- assertion_consumer_service_url: "http://localhost:3000/users/saml/auth",
240
+ assertion_consumer_service_url: "#{request.protocol}#{request.host_with_port}/users/saml/auth",
205
241
  assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
206
242
  name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
207
- issuer: "http://localhost:3000/saml/metadata",
243
+ issuer: "#{request.protocol}#{request.host_with_port}/saml/metadata",
208
244
  idp_entity_id: "http://www.example_idp_entity_id.com",
209
245
  authn_context: "",
210
- idp_slo_target_url: "http://example_idp_slo_target_url.com",
211
- idp_sso_target_url: "http://example_idp_sso_target_url.com",
246
+ idp_slo_service_url: "http://example_idp_slo_service_url.com",
247
+ idp_sso_service_url: "http://example_idp_sso_service_url.com",
212
248
  idp_cert: "example_idp_cert"
213
249
  }
214
250
  when "http://www.another_idp_entity_id.biz"
@@ -219,8 +255,8 @@ class IdPSettingsAdapter
219
255
  issuer: "http://localhost:3000/saml/metadata",
220
256
  idp_entity_id: "http://www.another_idp_entity_id.biz",
221
257
  authn_context: "",
222
- idp_slo_target_url: "http://another_idp_slo_target_url.com",
223
- idp_sso_target_url: "http://another_idp_sso_target_url.com",
258
+ idp_slo_service_url: "http://another_idp_slo_service_url.com",
259
+ idp_sso_service_url: "http://another_idp_sso_service_url.com",
224
260
  idp_cert: "another_idp_cert"
225
261
  }
226
262
  else
@@ -1,37 +1,33 @@
1
- require "ruby-saml"
1
+ require 'ruby-saml'
2
2
 
3
3
  class Devise::SamlSessionsController < Devise::SessionsController
4
4
  include DeviseSamlAuthenticatable::SamlConfig
5
- unloadable if Rails::VERSION::MAJOR < 4
6
- if Rails::VERSION::MAJOR < 5
7
- skip_before_filter :verify_authenticity_token
8
- prepend_before_filter :store_info_for_sp_initiated_logout, only: :destroy
9
- else
10
- skip_before_action :verify_authenticity_token, raise: false
11
- prepend_before_action :store_info_for_sp_initiated_logout, only: :destroy
12
- end
5
+
6
+ skip_before_action :verify_authenticity_token, raise: false
7
+ prepend_before_action :verify_signed_out_user, :store_info_for_sp_initiated_logout, only: :destroy
13
8
 
14
9
  def new
15
10
  idp_entity_id = get_idp_entity_id(params)
16
- request = OneLogin::RubySaml::Authrequest.new
11
+ auth_request = OneLogin::RubySaml::Authrequest.new
17
12
  auth_params = { RelayState: relay_state } if relay_state
18
- action = request.create(saml_config(idp_entity_id), auth_params || {})
19
- redirect_to action
13
+ action = auth_request.create(saml_config(idp_entity_id, request), auth_params || {})
14
+ session[:saml_transaction_id] = auth_request.request_id if auth_request.respond_to?(:request_id)
15
+ redirect_to action, allow_other_host: true
20
16
  end
21
17
 
22
18
  def metadata
23
19
  idp_entity_id = params[:idp_entity_id]
24
20
  meta = OneLogin::RubySaml::Metadata.new
25
- render :xml => meta.generate(saml_config(idp_entity_id))
21
+ render xml: meta.generate(saml_config(idp_entity_id, request))
26
22
  end
27
23
 
28
24
  def idp_sign_out
29
25
  if params[:SAMLRequest] && Devise.saml_session_index_key
30
- saml_config = saml_config(get_idp_entity_id(params))
26
+ saml_config = saml_config(get_idp_entity_id(params), request)
31
27
  logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest], settings: saml_config)
32
28
  resource_class.reset_session_key_for(logout_request.name_id)
33
29
 
34
- redirect_to generate_idp_logout_response(saml_config, logout_request.id)
30
+ redirect_to generate_idp_logout_response(saml_config, logout_request.id), allow_other_host: true
35
31
  elsif params[:SAMLResponse]
36
32
  # Currently Devise handles the session invalidation when the request is made.
37
33
  # To support a true SP initiated logout response, the request ID would have to be tracked and session invalidated
@@ -49,25 +45,26 @@ class Devise::SamlSessionsController < Devise::SessionsController
49
45
  protected
50
46
 
51
47
  def relay_state
52
- @relay_state ||= if Devise.saml_relay_state.present?
53
- Devise.saml_relay_state.call(request)
54
- end
48
+ @relay_state ||= (Devise.saml_relay_state.call(request) if Devise.saml_relay_state.present?)
55
49
  end
56
50
 
57
51
  # For non transient name ID, save info to identify user for logout purpose
58
52
  # before that user's session got destroyed. These info are used in the
59
53
  # `after_sign_out_path_for` method below.
60
54
  def store_info_for_sp_initiated_logout
61
- return if Devise.saml_config.name_identifier_format == "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
55
+ return if Devise.saml_config.name_identifier_format == 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
56
+
62
57
  @name_identifier_value_for_sp_initiated_logout = Devise.saml_name_identifier_retriever.call(current_user)
63
- @sessionindex_for_sp_initiated_logout = current_user.public_send(Devise.saml_session_index_key) if Devise.saml_session_index_key
58
+ if Devise.saml_session_index_key
59
+ @sessionindex_for_sp_initiated_logout = current_user.public_send(Devise.saml_session_index_key)
60
+ end
64
61
  end
65
62
 
66
63
  # Override devise to send user to IdP logout for SLO
67
64
  def after_sign_out_path_for(_)
68
65
  idp_entity_id = get_idp_entity_id(params)
69
- request = OneLogin::RubySaml::Logoutrequest.new
70
- saml_settings = saml_config(idp_entity_id).dup
66
+ logout_request = OneLogin::RubySaml::Logoutrequest.new
67
+ saml_settings = saml_config(idp_entity_id, request).dup
71
68
 
72
69
  # Add attributes to saml_settings which will later be used to create the SP
73
70
  # initiated logout request
@@ -76,15 +73,24 @@ class Devise::SamlSessionsController < Devise::SessionsController
76
73
  saml_settings.sessionindex = @sessionindex_for_sp_initiated_logout
77
74
  end
78
75
 
79
- request.create(saml_settings)
76
+ logout_request.create(saml_settings)
80
77
  end
81
78
 
82
- def generate_idp_logout_response(saml_config, logout_request_id)
79
+ # Overried devise: if user is signed out, not create the SP initiated logout request,
80
+ # redirect to saml_sign_out_success_url,
81
+ # or devise's after_sign_out_path_for
82
+ def verify_signed_out_user
83
+ if all_signed_out?
84
+ set_flash_message! :notice, :already_signed_out
83
85
 
84
- params = {}
85
- if relay_state
86
- params[:RelayState] = relay_state
86
+ redirect_to (Devise.saml_sign_out_success_url.presence ||
87
+ Devise::SessionsController.new.after_sign_out_path_for(resource_name)), allow_other_host: true
87
88
  end
89
+ end
90
+
91
+ def generate_idp_logout_response(saml_config, logout_request_id)
92
+ params = {}
93
+ params[:RelayState] = relay_state if relay_state
88
94
 
89
95
  OneLogin::RubySaml::SloLogoutresponse.new.create(saml_config, logout_request_id, nil, params)
90
96
  end
@@ -1,9 +1,9 @@
1
1
  module DeviseSamlAuthenticatable
2
2
 
3
3
  class Logger
4
- def self.send(message, logger = Rails.logger)
4
+ def self.send(message, log_level = ::Logger::INFO, logger = Rails.logger)
5
5
  if ::Devise.saml_logger
6
- logger.add 0, " \e[36msaml:\e[0m #{message}"
6
+ logger.add log_level, " \e[36msaml:\e[0m #{message}"
7
7
  end
8
8
  end
9
9
  end
@@ -55,8 +55,11 @@ module Devise
55
55
  end
56
56
  end
57
57
 
58
+ create_user = if Devise.saml_create_user.respond_to?(:call) then Devise.saml_create_user.call(self, decorated_response, auth_value)
59
+ else Devise.saml_create_user
60
+ end
58
61
  if resource.nil?
59
- if Devise.saml_create_user
62
+ if create_user
60
63
  logger.info("Creating user(#{auth_value}).")
61
64
  resource = new
62
65
  else
@@ -65,7 +68,10 @@ module Devise
65
68
  end
66
69
  end
67
70
 
68
- if Devise.saml_update_user || (resource.new_record? && Devise.saml_create_user)
71
+ update_user = if Devise.saml_update_user.respond_to?(:call) then Devise.saml_update_user.call(self, decorated_response, auth_value)
72
+ else Devise.saml_update_user
73
+ end
74
+ if update_user || (resource.new_record? && create_user)
69
75
  Devise.saml_update_resource_hook.call(resource, decorated_response, auth_value)
70
76
  end
71
77
 
@@ -1,9 +1,9 @@
1
1
  require 'ruby-saml'
2
2
  module DeviseSamlAuthenticatable
3
3
  module SamlConfig
4
- def saml_config(idp_entity_id = nil)
4
+ def saml_config(idp_entity_id = nil, request = nil)
5
5
  return file_based_config if file_based_config
6
- return adapter_based_config(idp_entity_id) if Devise.idp_settings_adapter
6
+ return adapter_based_config(idp_entity_id, request) if Devise.idp_settings_adapter
7
7
 
8
8
  Devise.saml_config
9
9
  end
@@ -19,10 +19,16 @@ module DeviseSamlAuthenticatable
19
19
  end
20
20
  end
21
21
 
22
- def adapter_based_config(idp_entity_id)
22
+ def adapter_based_config(idp_entity_id, request)
23
23
  config = Marshal.load(Marshal.dump(Devise.saml_config))
24
24
 
25
- idp_settings_adapter.settings(idp_entity_id).each do |k,v|
25
+ if idp_settings_adapter.method(:settings).parameters.length == 1
26
+ settings = idp_settings_adapter.settings(idp_entity_id)
27
+ else
28
+ settings = idp_settings_adapter.settings(idp_entity_id, request)
29
+ end
30
+
31
+ settings.each do |k,v|
26
32
  acc = "#{k.to_s}=".to_sym
27
33
 
28
34
  if config.respond_to? acc
@@ -8,8 +8,7 @@ module Devise
8
8
  if params[:SAMLResponse]
9
9
  OneLogin::RubySaml::Response.new(
10
10
  params[:SAMLResponse],
11
- settings: saml_config(get_idp_entity_id(params)),
12
- allowed_clock_drift: Devise.allowed_clock_drift_in_seconds,
11
+ response_options,
13
12
  )
14
13
  else
15
14
  false
@@ -36,8 +35,7 @@ module Devise
36
35
  def parse_saml_response
37
36
  @response = OneLogin::RubySaml::Response.new(
38
37
  params[:SAMLResponse],
39
- settings: saml_config(get_idp_entity_id(params)),
40
- allowed_clock_drift: Devise.allowed_clock_drift_in_seconds,
38
+ response_options,
41
39
  )
42
40
  unless @response.is_valid?
43
41
  failed_auth("Auth errors: #{@response.errors.join(', ')}")
@@ -54,9 +52,29 @@ module Devise
54
52
  def failed_auth(msg)
55
53
  DeviseSamlAuthenticatable::Logger.send(msg)
56
54
  fail!(:invalid)
57
- Devise.saml_failed_callback.new.handle(@response, self) if Devise.saml_failed_callback
55
+ failed_callback.new.handle(@response, self) if Devise.saml_failed_callback
56
+ end
57
+
58
+ def failed_callback
59
+ if Devise.saml_failed_callback.respond_to?(:new)
60
+ Devise.saml_failed_callback
61
+ else
62
+ Devise.saml_failed_callback.constantize
63
+ end
58
64
  end
59
65
 
66
+ def response_options
67
+ options = {
68
+ settings: saml_config(get_idp_entity_id(params), request),
69
+ allowed_clock_drift: Devise.allowed_clock_drift_in_seconds,
70
+ }
71
+
72
+ if Devise.saml_validate_in_response_to
73
+ options[:matches_request_id] = request.session[:saml_transaction_id] || "ID_MISSING"
74
+ end
75
+
76
+ options
77
+ end
60
78
  end
61
79
  end
62
80
  end
@@ -1,3 +1,3 @@
1
1
  module DeviseSamlAuthenticatable
2
- VERSION = "1.6.3"
2
+ VERSION = "1.9.0"
3
3
  end
@@ -29,10 +29,20 @@ module Devise
29
29
  @@saml_logger = true
30
30
 
31
31
  # Add valid users to database
32
+ # Can accept a Boolean value or a Proc that is called with the model class, the saml_response and auth_value
33
+ # Ex:
34
+ # Devise.saml_create_user = Proc.new do |model_class, saml_response, auth_value|
35
+ # model_class == Admin
36
+ # end
32
37
  mattr_accessor :saml_create_user
33
38
  @@saml_create_user = false
34
39
 
35
40
  # Update user attributes after login
41
+ # Can accept a Boolean value or a Proc that is called with the model class, the saml_response and auth_value
42
+ # Ex:
43
+ # Devise.saml_update_user = Proc.new do |model_class, saml_response, auth_value|
44
+ # model_class == User
45
+ # end
36
46
  mattr_accessor :saml_update_user
37
47
  @@saml_update_user = false
38
48
 
@@ -67,6 +77,10 @@ module Devise
67
77
  mattr_accessor :saml_relay_state
68
78
  @@saml_relay_state
69
79
 
80
+ # Validate that the InResponseTo header in SAML responses matches the ID of the request.
81
+ mattr_accessor :saml_validate_in_response_to
82
+ @@saml_validate_in_response_to = false
83
+
70
84
  # Instead of storing the attribute_map in attribute-map.yml, store it in the database, or set it programatically
71
85
  mattr_accessor :saml_attribute_map_resolver
72
86
  @@saml_attribute_map_resolver ||= "::DeviseSamlAuthenticatable::DefaultAttributeMapResolver"