devise_saml_authenticatable 1.4.0 → 1.6.2

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.
Files changed (36) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -2
  3. data/.travis.yml +27 -24
  4. data/Gemfile +2 -2
  5. data/README.md +99 -30
  6. data/app/controllers/devise/saml_sessions_controller.rb +34 -7
  7. data/devise_saml_authenticatable.gemspec +1 -1
  8. data/lib/devise_saml_authenticatable.rb +25 -0
  9. data/lib/devise_saml_authenticatable/default_attribute_map_resolver.rb +26 -0
  10. data/lib/devise_saml_authenticatable/exception.rb +1 -1
  11. data/lib/devise_saml_authenticatable/model.rb +10 -17
  12. data/lib/devise_saml_authenticatable/routes.rb +17 -6
  13. data/lib/devise_saml_authenticatable/saml_mapped_attributes.rb +15 -2
  14. data/lib/devise_saml_authenticatable/strategy.rb +1 -1
  15. data/lib/devise_saml_authenticatable/version.rb +1 -1
  16. data/spec/controllers/devise/saml_sessions_controller_spec.rb +69 -11
  17. data/spec/devise_saml_authenticatable/default_attribute_map_resolver_spec.rb +58 -0
  18. data/spec/devise_saml_authenticatable/model_spec.rb +55 -7
  19. data/spec/devise_saml_authenticatable/saml_mapped_attributes_spec.rb +50 -0
  20. data/spec/features/saml_authentication_spec.rb +45 -37
  21. data/spec/rails_helper.rb +6 -2
  22. data/spec/routes/routes_spec.rb +102 -0
  23. data/spec/spec_helper.rb +7 -0
  24. data/spec/support/Gemfile.rails4 +20 -10
  25. data/spec/support/Gemfile.rails5 +13 -2
  26. data/spec/support/Gemfile.rails5.1 +25 -0
  27. data/spec/support/Gemfile.rails5.2 +25 -0
  28. data/spec/support/attribute-map.yml +12 -0
  29. data/spec/support/attribute_map_resolver.rb.erb +14 -0
  30. data/spec/support/idp_settings_adapter.rb.erb +5 -5
  31. data/spec/support/idp_template.rb +6 -2
  32. data/spec/support/rails_app.rb +75 -17
  33. data/spec/support/saml_idp_controller.rb.erb +13 -6
  34. data/spec/support/sp_template.rb +45 -21
  35. metadata +23 -12
  36. data/spec/support/Gemfile.ruby-saml-1.3 +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9a26db022c02d24566654e1d965c374a0e3b3380
4
- data.tar.gz: 1341712900741f3c7326ddb7f099468bbc1d1066
2
+ SHA256:
3
+ metadata.gz: c0d1e1f1df121795583d9fc25cab40edac01bb61f8adbdb4fac7c0c15bfe4b0c
4
+ data.tar.gz: 0d7770994b0c119da178a3b19ced6d52a88364d561279c5bd759ce5580fb5fe5
5
5
  SHA512:
6
- metadata.gz: 9ee3d6d7075cccdb05b87c8cea6e7f9feab58d3f2a0ae4fc1cbc9d6e679b82d1c59e675195c520867903808070cc8e9fb49ff99028b7816f039e029f0d455a6a
7
- data.tar.gz: 9ea8211cda495a8347e5e2672214e5fc8448e232ca1d961645dde9f22b18eaf9bd6bcf8e6876dea110cbe2292a8d01fdc303039629cbe781f3901a15ab73efc8
6
+ metadata.gz: d849dc5dff4bd09d0dd034449ed3e68494f0f1c82c8e31c708b7d6e0d3a366a2fd119fb24704d0e5a946b6fc206dbe072fadbf7218489abffdbe1b3644d41419
7
+ data.tar.gz: e64b35109ed35b61e804fa5e06d3b3c299210cf75804f706e299147d02a7ddb929246c1a7fdb65aee12f5ceed5348267d3c6e4657544288e3a45741474d5e30d
data/.gitignore CHANGED
@@ -13,6 +13,4 @@ lib/bundler/man
13
13
  pkg
14
14
  rdoc
15
15
  spec/reports
16
- spec/support/idp/
17
- spec/support/sp/
18
16
  tmp
@@ -1,49 +1,52 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9.3"
4
3
  - "2.0.0"
5
4
  - "2.1.10"
6
- - "2.2.7"
7
- - "2.3.4"
8
- - "2.4.1"
5
+ - "2.2.10"
6
+ - "2.3.8"
7
+ - "2.4.10"
8
+ - "2.5.8"
9
+ - "2.6.6"
10
+ - "2.7.1"
9
11
  gemfile:
10
12
  - Gemfile
13
+ - spec/support/Gemfile.rails5.2
14
+ - spec/support/Gemfile.rails5.1
11
15
  - spec/support/Gemfile.rails5
12
16
  - spec/support/Gemfile.rails4
13
- - spec/support/Gemfile.ruby-saml-1.3
14
17
  matrix:
15
18
  allow_failures:
16
- - rvm: "1.9.3"
17
- gemfile: Gemfile
18
- - rvm: "1.9.3"
19
- gemfile: spec/support/Gemfile.rails5
20
- - rvm: "1.9.3"
21
- gemfile: spec/support/Gemfile.ruby-saml-1.3
22
19
  - rvm: "2.0.0"
23
20
  gemfile: Gemfile
24
21
  - rvm: "2.0.0"
25
22
  gemfile: spec/support/Gemfile.rails5
26
23
  - rvm: "2.0.0"
27
- gemfile: spec/support/Gemfile.ruby-saml-1.3
24
+ gemfile: spec/support/Gemfile.rails5.1
25
+ - rvm: "2.0.0"
26
+ gemfile: spec/support/Gemfile.rails5.2
28
27
  - rvm: "2.1.10"
29
28
  gemfile: Gemfile
30
29
  - rvm: "2.1.10"
31
30
  gemfile: spec/support/Gemfile.rails5
32
31
  - rvm: "2.1.10"
33
- gemfile: spec/support/Gemfile.ruby-saml-1.3
32
+ gemfile: spec/support/Gemfile.rails5.1
33
+ - rvm: "2.1.10"
34
+ gemfile: spec/support/Gemfile.rails5.2
35
+ - rvm: "2.2.10"
36
+ gemfile: Gemfile
37
+ - rvm: "2.2.10"
38
+ gemfile: spec/support/Gemfile.rails5.2
39
+ - rvm: "2.3.8"
40
+ gemfile: Gemfile
41
+ - rvm: "2.4.10"
42
+ gemfile: Gemfile
43
+ - rvm: "2.6.6"
44
+ gemfile: spec/support/Gemfile.rails4
45
+ - rvm: "2.7.1"
46
+ gemfile: spec/support/Gemfile.rails4
34
47
 
35
48
  before_install:
36
- # update bundler to avoid https://github.com/travis-ci/travis-ci/issues/5239
37
- - gem install bundler
49
+ - command -v bundle || gem install bundler -v '~> 1.17.3'
38
50
 
39
51
  script:
40
52
  - bundle exec rake
41
-
42
- notifications:
43
- hipchat:
44
- rooms:
45
- secure: cuDak5a6fBeg+sp61COqxQfzdcFEsjwCqtwvCISso0RNh5SR8v+uVYKcA8rlK+GE1l9uR7tLRHeHF3ZmzvFSOat07NvpScvjZXi+OSpWlc6rwQ6Pl6bBP6gu6sREiKVe0eT/uGrvJloyWKZaXIhiiBzQ+ZERx/ssGA9WMmNkhlwy1OgGnPNurNNHZLBjEZn1V6kdyxiXx6QPASNpjNEgN1G8dUh3qzcWUGVQGNZSJk65A6ie1MveNyecTjDhw+ADBU8nS28Ja4y6ohRm4FzofSgespYrvfygIZ5rYF0HPMj5FW1ZDWtM5355ojCk8RLT+ZkuhssCn1OJk7ogaOVjnYcOFRxEfpu3eIbjtMmUz3j4umatFqbgas+6SXMVIPkr5HUoTrP8HNFssIpcEBOnPwAF8QCpx+daHc0r2cc8lGuXhtJfpW0P2F0dmwJNiQ7//nz2y2xs84x4Gb7MV9tEDYp0FqEClMuFBkPNizBljarm04PkiLSrqvR52aMDfQz7YAX2oXAvFjPzI1GC0K8x7xX8TuHT9yuHy7fI+rUSNivZYLKO+IEZqPPDdJpXISUbVwanZoNvmQYk5PZV21MfDSGwQrz8eO/uFiAblj18yIlNbAfb2hdZDVYsm4EvWxELJtfaTxgrj6M3Y3m/KbCbCoDp+2jE307M2rxL0Gum2gk=
46
- template:
47
- - '%{repository}<a href="%{build_url}">#%{build_number}</a> (%{branch} - <a href="%{compare_url}">%{commit}</a> : %{author}): %{message}'
48
- format: html
49
- on_pull_requests: true
data/Gemfile CHANGED
@@ -6,9 +6,9 @@ gemspec
6
6
  group :test do
7
7
  gem 'rake'
8
8
  gem 'rspec', '~> 3.0'
9
- gem 'rails', '~> 5.1'
9
+ gem 'rails', '~> 6.0'
10
10
  gem 'rspec-rails'
11
- gem 'sqlite3'
11
+ gem 'sqlite3', '~> 1.4.0'
12
12
  gem 'capybara'
13
13
  gem 'poltergeist'
14
14
  end
data/README.md CHANGED
@@ -6,19 +6,20 @@ It uses [ruby-saml][] to handle all SAML-related stuff.
6
6
 
7
7
  ## Installation
8
8
 
9
- Add this line to your application's Gemfile:
9
+ Add this gem to your application's Gemfile:
10
10
 
11
- gem 'devise_saml_authenticatable'
11
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
12
+ gem "devise_saml_authenticatable", github: "apokalipto/devise_saml_authenticatable"
12
13
 
13
14
  And then execute:
14
15
 
15
16
  $ bundle
16
17
 
17
- Or install it yourself as:
18
+ ## Usage
18
19
 
19
- $ gem install devise_saml_authenticatable
20
+ 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.
20
21
 
21
- ## Usage
22
+ ### Configuring Models
22
23
 
23
24
  In `app/models/<YOUR_MODEL>.rb` set the `:saml_authenticatable` strategy.
24
25
 
@@ -32,6 +33,37 @@ In the example the model is `user.rb`:
32
33
  end
33
34
  ```
34
35
 
36
+ ### Configuring routes
37
+
38
+ In `config/routes.rb` add `devise_for` to set up helper methods and routes:
39
+
40
+ ```ruby
41
+ devise_for :users
42
+ ```
43
+
44
+ The named routes can be customized in the initializer config file.
45
+
46
+ ### Configuring the IdP
47
+
48
+ 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.
49
+
50
+ - Creating a new session: `/users/saml/auth`
51
+ - 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.
52
+ - Metadata: `/users/saml/metadata`
53
+ - IdPs may call this the "audience."
54
+ - Single Logout: `/users/saml/idp_sign_out`
55
+ - 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.
56
+
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
+
59
+ - Issuer (`idp_entity_id`)
60
+ - SSO endpoint (`idp_sso_target_url`)
61
+ - SLO endpoint (`idp_slo_target_url`)
62
+ - Certificate fingerprint (`idp_cert_fingerprint`) and algorithm (`idp_cert_fingerprint_algorithm`)
63
+ - Or the certificate itself (`idp_cert`)
64
+
65
+ ### Configuring handling of IdP requests and responses
66
+
35
67
  In `config/initializers/devise.rb`:
36
68
 
37
69
  ```ruby
@@ -69,6 +101,16 @@ In `config/initializers/devise.rb`:
69
101
  # and implements a #handle method. This method can then redirect the user, return error messages, etc.
70
102
  # config.saml_failed_callback = nil
71
103
 
104
+ # You can customize the named routes generated in case of named route collisions with
105
+ # other Devise modules or libraries. Set the saml_route_helper_prefix to a string that will
106
+ # be appended to the named route.
107
+ # If saml_route_helper_prefix = 'saml' then the new_user_session route becomes new_saml_user_session
108
+ # config.saml_route_helper_prefix = 'saml'
109
+
110
+ # You can add allowance for clock drift between the sp and idp.
111
+ # This is a time in seconds.
112
+ # config.allowed_clock_drift_in_seconds = 0
113
+
72
114
  # Configure with your SAML settings (see ruby-saml's README for more information: https://github.com/onelogin/ruby-saml).
73
115
  config.saml_configure do |settings|
74
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
@@ -79,29 +121,32 @@ In `config/initializers/devise.rb`:
79
121
  settings.authn_context = ""
80
122
  settings.idp_slo_target_url = "http://localhost/simplesaml/www/saml2/idp/SingleLogoutService.php"
81
123
  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
124
+ 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
+ settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
100
126
  end
101
127
  end
102
128
  ```
103
129
 
104
- In the config directory, create a YAML file (`attribute-map.yml`) that maps SAML attributes with your model's fields:
130
+ #### Attributes
131
+
132
+ There are two ways to map SAML attributes to User attributes:
133
+
134
+ - [initializer](#attribute-map-initializer)
135
+ - [config file](#attribute-map-config-file)
136
+
137
+ The attribute mappings are very dependent on the way the IdP encodes the attributes.
138
+ In these examples the attributes are given in URN style.
139
+ Other IdPs might provide them as OID's, or by other means.
140
+
141
+ You are now ready to test it against an IdP.
142
+
143
+ When the user visits `/users/saml/sign_in` they will be redirected to the login page of the IdP.
144
+
145
+ Upon successful login the user is redirected to the Devise `user_root_path`.
146
+
147
+ ##### Attribute map config file
148
+
149
+ Create a YAML file (`config/attribute-map.yml`) that maps SAML attributes with your model's fields:
105
150
 
106
151
  ```yaml
107
152
  # attribute-map.yml
@@ -112,15 +157,39 @@ In the config directory, create a YAML file (`attribute-map.yml`) that maps SAML
112
157
  "urn:mace:dir:attribute-def:givenName": "name"
113
158
  ```
114
159
 
115
- The attribute mappings are very dependent on the way the IdP encodes the attributes.
116
- In this example the attributes are given in URN style.
117
- Other IdPs might provide them as OID's, or by other means.
160
+ ##### Attribute map initializer
118
161
 
119
- You are now ready to test it against an IdP.
162
+ In `config/initializers/devise.rb` (see above), add an attribute map resolver.
163
+ The resolver gets the [SAML response from the IdP](https://github.com/onelogin/ruby-saml/blob/master/lib/onelogin/ruby-saml/response.rb) so it can decide which attribute map to load.
164
+ If you only have one IdP, you can use the config file above, or just return a single hash.
120
165
 
121
- When the user visits `/users/saml/sign_in` they will be redirected to the login page of the IdP.
166
+ ```ruby
167
+ # config/initializers/devise.rb
168
+ Devise.setup do |config|
169
+ ...
170
+ # ==> Configuration for :saml_authenticatable
122
171
 
123
- Upon successful login the user is redirected to the Devise `user_root_path`.
172
+ config.saml_attribute_map_resolver = MyAttributeMapResolver
173
+ end
174
+ ```
175
+
176
+ ```ruby
177
+ # app/lib/my_attribute_map_resolver
178
+ class MyAttributeMapResolver < DeviseSamlAuthenticatable::DefaultAttributeMapResolver
179
+ def attribute_map
180
+ issuer = saml_response.issuers.first
181
+ case issuer
182
+ when "idp_entity_id"
183
+ {
184
+ "urn:mace:dir:attribute-def:uid" => "user_name",
185
+ "urn:mace:dir:attribute-def:email" => "email",
186
+ "urn:mace:dir:attribute-def:name" => "last_name",
187
+ "urn:mace:dir:attribute-def:givenName" => "name",
188
+ }
189
+ end
190
+ end
191
+ end
192
+ ```
124
193
 
125
194
  ## Supporting Multiple IdPs
126
195
 
@@ -5,8 +5,10 @@ class Devise::SamlSessionsController < Devise::SessionsController
5
5
  unloadable if Rails::VERSION::MAJOR < 4
6
6
  if Rails::VERSION::MAJOR < 5
7
7
  skip_before_filter :verify_authenticity_token
8
+ prepend_before_filter :store_info_for_sp_initiated_logout, only: :destroy
8
9
  else
9
10
  skip_before_action :verify_authenticity_token, raise: false
11
+ prepend_before_action :store_info_for_sp_initiated_logout, only: :destroy
10
12
  end
11
13
 
12
14
  def new
@@ -18,8 +20,9 @@ class Devise::SamlSessionsController < Devise::SessionsController
18
20
  end
19
21
 
20
22
  def metadata
23
+ idp_entity_id = params[:idp_entity_id]
21
24
  meta = OneLogin::RubySaml::Metadata.new
22
- render :xml => meta.generate(saml_config)
25
+ render :xml => meta.generate(saml_config(idp_entity_id))
23
26
  end
24
27
 
25
28
  def idp_sign_out
@@ -30,16 +33,16 @@ class Devise::SamlSessionsController < Devise::SessionsController
30
33
 
31
34
  redirect_to generate_idp_logout_response(saml_config, logout_request.id)
32
35
  elsif params[:SAMLResponse]
33
- #Currently Devise handles the session invalidation when the request is made.
34
- #To support a true SP initiated logout response, the request ID would have to be tracked and session invalidated
35
- #based on that.
36
+ # Currently Devise handles the session invalidation when the request is made.
37
+ # To support a true SP initiated logout response, the request ID would have to be tracked and session invalidated
38
+ # based on that.
36
39
  if Devise.saml_sign_out_success_url
37
40
  redirect_to Devise.saml_sign_out_success_url
38
41
  else
39
42
  redirect_to action: :new
40
43
  end
41
44
  else
42
- head :invalid_request
45
+ head 500
43
46
  end
44
47
  end
45
48
 
@@ -51,14 +54,38 @@ class Devise::SamlSessionsController < Devise::SessionsController
51
54
  end
52
55
  end
53
56
 
57
+ # For non transient name ID, save info to identify user for logout purpose
58
+ # before that user's session got destroyed. These info are used in the
59
+ # `after_sign_out_path_for` method below.
60
+ 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"
62
+ @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
64
+ end
65
+
54
66
  # Override devise to send user to IdP logout for SLO
55
67
  def after_sign_out_path_for(_)
56
68
  idp_entity_id = get_idp_entity_id(params)
57
69
  request = OneLogin::RubySaml::Logoutrequest.new
58
- request.create(saml_config(idp_entity_id))
70
+ saml_settings = saml_config(idp_entity_id).dup
71
+
72
+ # Add attributes to saml_settings which will later be used to create the SP
73
+ # initiated logout request
74
+ unless Devise.saml_config.name_identifier_format == 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
75
+ saml_settings.name_identifier_value = @name_identifier_value_for_sp_initiated_logout
76
+ saml_settings.sessionindex = @sessionindex_for_sp_initiated_logout
77
+ end
78
+
79
+ request.create(saml_settings)
59
80
  end
60
81
 
61
82
  def generate_idp_logout_response(saml_config, logout_request_id)
62
- OneLogin::RubySaml::SloLogoutresponse.new.create(saml_config, logout_request_id, nil)
83
+
84
+ params = {}
85
+ if relay_state
86
+ params[:RelayState] = relay_state
87
+ end
88
+
89
+ OneLogin::RubySaml::SloLogoutresponse.new.create(saml_config, logout_request_id, nil, params)
63
90
  end
64
91
  end
@@ -18,5 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
 
20
20
  gem.add_dependency("devise","> 2.0.0")
21
- gem.add_dependency("ruby-saml","~> 1.3")
21
+ gem.add_dependency("ruby-saml","~> 1.7")
22
22
  end
@@ -5,6 +5,7 @@ require "devise_saml_authenticatable/exception"
5
5
  require "devise_saml_authenticatable/logger"
6
6
  require "devise_saml_authenticatable/routes"
7
7
  require "devise_saml_authenticatable/saml_config"
8
+ require "devise_saml_authenticatable/default_attribute_map_resolver"
8
9
  require "devise_saml_authenticatable/default_idp_entity_id_reader"
9
10
 
10
11
  begin
@@ -19,6 +20,10 @@ end
19
20
 
20
21
  # Get saml information from config/saml.yml now
21
22
  module Devise
23
+ # Allow route customization to avoid collision
24
+ mattr_accessor :saml_route_helper_prefix
25
+ @@saml_route_helper_prefix
26
+
22
27
  # Allow logging
23
28
  mattr_accessor :saml_logger
24
29
  @@saml_logger = true
@@ -62,11 +67,23 @@ module Devise
62
67
  mattr_accessor :saml_relay_state
63
68
  @@saml_relay_state
64
69
 
70
+ # Instead of storing the attribute_map in attribute-map.yml, store it in the database, or set it programatically
71
+ mattr_accessor :saml_attribute_map_resolver
72
+ @@saml_attribute_map_resolver ||= ::DeviseSamlAuthenticatable::DefaultAttributeMapResolver
73
+
65
74
  # Implements a #validate method that takes the retrieved resource and response right after retrieval,
66
75
  # and returns true if it's valid. False will cause authentication to fail.
76
+ # Only one of saml_resource_validator and saml_resource_validator_hook may be used.
67
77
  mattr_accessor :saml_resource_validator
68
78
  @@saml_resource_validator
69
79
 
80
+ # Proc that determines whether a technically correct SAML response is valid per some custom logic.
81
+ # Receives the user object (or nil, if no match was found), decorated saml_response and
82
+ # auth_value, inspects the combination for acceptability of login (or create+login, if enabled),
83
+ # and returns true if it's valid. False will cause authentication to fail.
84
+ mattr_accessor :saml_resource_validator_hook
85
+ @@saml_resource_validator_hook
86
+
70
87
  # Custom value for ruby-saml allowed_clock_drift
71
88
  mattr_accessor :allowed_clock_drift_in_seconds
72
89
  @@allowed_clock_drift_in_seconds
@@ -112,6 +129,14 @@ module Devise
112
129
  # See saml_default_resource_locator above for an example.
113
130
  mattr_accessor :saml_resource_locator
114
131
  @@saml_resource_locator = @@saml_default_resource_locator
132
+
133
+ # Proc that is called to resolve the name identifier to use in a LogoutRequest for the current user.
134
+ # Receives the logged-in user.
135
+ # Is expected to return the identifier the IdP understands for this user, e.g. email address or username.
136
+ mattr_accessor :saml_name_identifier_retriever
137
+ @@saml_name_identifier_retriever = Proc.new do |current_user|
138
+ current_user.public_send(Devise.saml_default_user_key)
139
+ end
115
140
  end
116
141
 
117
142
  # Add saml_authenticatable strategy to defaults.
@@ -0,0 +1,26 @@
1
+ module DeviseSamlAuthenticatable
2
+ class DefaultAttributeMapResolver
3
+ def initialize(saml_response)
4
+ @saml_response = saml_response
5
+ end
6
+
7
+ def attribute_map
8
+ return {} unless File.exist?(attribute_map_path)
9
+
10
+ attribute_map = YAML.load(File.read(attribute_map_path))
11
+ if attribute_map.key?(Rails.env)
12
+ attribute_map[Rails.env]
13
+ else
14
+ attribute_map
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :saml_response
21
+
22
+ def attribute_map_path
23
+ Rails.root.join("config", "attribute-map.yml")
24
+ end
25
+ end
26
+ end