devise_saml_authenticatable 1.6.3 → 1.9.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
  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"