devise_saml_authenticatable 1.3.2 → 1.4.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 +4 -4
- data/.travis.yml +4 -0
- data/README.md +6 -2
- data/app/controllers/devise/saml_sessions_controller.rb +2 -1
- data/devise_saml_authenticatable.gemspec +1 -0
- data/lib/devise_saml_authenticatable.rb +2 -2
- data/lib/devise_saml_authenticatable/default_idp_entity_id_reader.rb +2 -0
- data/lib/devise_saml_authenticatable/strategy.rb +1 -0
- data/lib/devise_saml_authenticatable/version.rb +1 -1
- data/spec/controllers/devise/saml_sessions_controller_spec.rb +53 -4
- data/spec/features/saml_authentication_spec.rb +18 -2
- data/spec/support/Gemfile.rails4 +8 -1
- data/spec/support/Gemfile.ruby-saml-1.3 +1 -3
- data/spec/support/idp_settings_adapter.rb.erb +2 -2
- data/spec/support/sp_template.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a26db022c02d24566654e1d965c374a0e3b3380
|
4
|
+
data.tar.gz: 1341712900741f3c7326ddb7f099468bbc1d1066
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ee3d6d7075cccdb05b87c8cea6e7f9feab58d3f2a0ae4fc1cbc9d6e679b82d1c59e675195c520867903808070cc8e9fb49ff99028b7816f039e029f0d455a6a
|
7
|
+
data.tar.gz: 9ea8211cda495a8347e5e2672214e5fc8448e232ca1d961645dde9f22b18eaf9bd6bcf8e6876dea110cbe2292a8d01fdc303039629cbe781f3901a15ab73efc8
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -69,8 +69,9 @@ In `config/initializers/devise.rb`:
|
|
69
69
|
# and implements a #handle method. This method can then redirect the user, return error messages, etc.
|
70
70
|
# config.saml_failed_callback = nil
|
71
71
|
|
72
|
-
# Configure with your SAML settings (see
|
72
|
+
# Configure with your SAML settings (see ruby-saml's README for more information: https://github.com/onelogin/ruby-saml).
|
73
73
|
config.saml_configure do |settings|
|
74
|
+
# assertion_consumer_service_url is required starting with ruby-saml 1.4.3: https://github.com/onelogin/ruby-saml#updating-from-142-to-143
|
74
75
|
settings.assertion_consumer_service_url = "http://localhost:3000/users/saml/auth"
|
75
76
|
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
76
77
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
@@ -159,6 +160,7 @@ class IdPSettingsAdapter
|
|
159
160
|
end
|
160
161
|
end
|
161
162
|
```
|
163
|
+
Settings specified in the adapter will override settings in `config/initializers/devise.rb`. This is useful for establishing common settings or defaults across all IdPs.
|
162
164
|
|
163
165
|
Detecting the entity ID passed to the `settings` method is done by `config.idp_entity_id_reader`.
|
164
166
|
|
@@ -192,10 +194,12 @@ Logout requests from the IDP are supported by the `idp_sign_out` endpoint. Dire
|
|
192
194
|
|
193
195
|
`saml_session_index_key` must be configured to support this feature.
|
194
196
|
|
195
|
-
## Signing and Encrypting Authentication Requests
|
197
|
+
## Signing and Encrypting Authentication Requests and Assertions
|
196
198
|
|
197
199
|
ruby-saml 1.0.0 supports signature and decrypt. The only requirement is to set the public certificate and the private key. For more information, see [the ruby-saml documentation](https://github.com/onelogin/ruby-saml#signing).
|
198
200
|
|
201
|
+
If you have multiple IdPs, the certificate and private key must be in the shared settings in `config/initializers/devise.rb`.
|
202
|
+
|
199
203
|
## Thanks
|
200
204
|
|
201
205
|
The continued maintenance of this gem could not have been possible without the hard work of [Adam Stegman](https://github.com/adamstegman) and [Mitch Lindsay](https://github.com/mitch-lindsay). Thank you guys for keeping this project alive.
|
@@ -53,8 +53,9 @@ class Devise::SamlSessionsController < Devise::SessionsController
|
|
53
53
|
|
54
54
|
# Override devise to send user to IdP logout for SLO
|
55
55
|
def after_sign_out_path_for(_)
|
56
|
+
idp_entity_id = get_idp_entity_id(params)
|
56
57
|
request = OneLogin::RubySaml::Logoutrequest.new
|
57
|
-
request.create(saml_config)
|
58
|
+
request.create(saml_config(idp_entity_id))
|
58
59
|
end
|
59
60
|
|
60
61
|
def generate_idp_logout_response(saml_config, logout_request_id)
|
@@ -7,6 +7,7 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.description = %q{SAML Authentication for devise}
|
8
8
|
gem.summary = %q{SAML Authentication for devise }
|
9
9
|
gem.homepage = ""
|
10
|
+
gem.license = "MIT"
|
10
11
|
|
11
12
|
gem.files = `git ls-files`.split($\)
|
12
13
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -94,7 +94,7 @@ module Devise
|
|
94
94
|
end
|
95
95
|
|
96
96
|
# Proc that is called if Devise.saml_update_user and/or Devise.saml_create_user are true.
|
97
|
-
#
|
97
|
+
# Receives the user object, saml_response and auth_value, and defines how the object's values are
|
98
98
|
# updated with regards to the SAML response. See saml_default_update_resource_hook for an example.
|
99
99
|
mattr_accessor :saml_update_resource_hook
|
100
100
|
@@saml_update_resource_hook = @@saml_default_update_resource_hook
|
@@ -107,7 +107,7 @@ module Devise
|
|
107
107
|
end
|
108
108
|
|
109
109
|
# Proc that is called to resolve the saml_response and auth_value into the correct user object.
|
110
|
-
#
|
110
|
+
# Receives a copy of the ActiveRecord::Model, saml_response and auth_value. Is expected to return
|
111
111
|
# one instance of the provided model that is the matched account, or nil if none exists.
|
112
112
|
# See saml_default_resource_locator above for an example.
|
113
113
|
mattr_accessor :saml_resource_locator
|
@@ -4,11 +4,13 @@ module DeviseSamlAuthenticatable
|
|
4
4
|
if params[:SAMLRequest]
|
5
5
|
OneLogin::RubySaml::SloLogoutrequest.new(
|
6
6
|
params[:SAMLRequest],
|
7
|
+
settings: Devise.saml_config,
|
7
8
|
allowed_clock_drift: Devise.allowed_clock_drift_in_seconds,
|
8
9
|
).issuer
|
9
10
|
elsif params[:SAMLResponse]
|
10
11
|
OneLogin::RubySaml::Response.new(
|
11
12
|
params[:SAMLResponse],
|
13
|
+
settings: Devise.saml_config,
|
12
14
|
allowed_clock_drift: Devise.allowed_clock_drift_in_seconds,
|
13
15
|
).issuers.first
|
14
16
|
end
|
@@ -66,6 +66,7 @@ describe Devise::SamlSessionsController, type: :controller do
|
|
66
66
|
it "uses the DefaultIdpEntityIdReader" do
|
67
67
|
expect(DeviseSamlAuthenticatable::DefaultIdpEntityIdReader).to receive(:entity_id)
|
68
68
|
do_get
|
69
|
+
expect(idp_providers_adapter).to have_received(:settings).with(nil)
|
69
70
|
end
|
70
71
|
|
71
72
|
context "with a relay_state lambda defined" do
|
@@ -104,6 +105,7 @@ describe Devise::SamlSessionsController, type: :controller do
|
|
104
105
|
|
105
106
|
it "redirects to the associated IdP SSO target url" do
|
106
107
|
do_get
|
108
|
+
expect(idp_providers_adapter).to have_received(:settings).with("http://www.example.com")
|
107
109
|
expect(response).to redirect_to(%r(\Ahttp://idp_sso_url\?SAMLRequest=))
|
108
110
|
end
|
109
111
|
end
|
@@ -147,10 +149,57 @@ describe Devise::SamlSessionsController, type: :controller do
|
|
147
149
|
end
|
148
150
|
|
149
151
|
describe '#destroy' do
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
152
|
+
context "when using the default saml config" do
|
153
|
+
it 'signs out and redirects to the IdP' do
|
154
|
+
expect(controller).to receive(:sign_out)
|
155
|
+
delete :destroy
|
156
|
+
expect(response).to redirect_to(%r(\Ahttp://localhost:8009/saml/logout\?SAMLRequest=))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context "with a specified idp" do
|
161
|
+
before do
|
162
|
+
Devise.idp_settings_adapter = idp_providers_adapter
|
163
|
+
end
|
164
|
+
|
165
|
+
it "redirects to the associated IdP SSO target url" do
|
166
|
+
expect(controller).to receive(:sign_out)
|
167
|
+
expect(DeviseSamlAuthenticatable::DefaultIdpEntityIdReader).to receive(:entity_id)
|
168
|
+
delete :destroy
|
169
|
+
expect(response).to redirect_to(%r(\Ahttp://idp_slo_url\?SAMLRequest=))
|
170
|
+
end
|
171
|
+
|
172
|
+
context "with a specified idp entity id reader" do
|
173
|
+
class OurIdpEntityIdReader
|
174
|
+
def self.entity_id(params)
|
175
|
+
params[:entity_id]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
subject(:do_delete) {
|
180
|
+
if Rails::VERSION::MAJOR > 4
|
181
|
+
delete :destroy, params: {entity_id: "http://www.example.com"}
|
182
|
+
else
|
183
|
+
delete :destroy, entity_id: "http://www.example.com"
|
184
|
+
end
|
185
|
+
}
|
186
|
+
|
187
|
+
before do
|
188
|
+
@default_reader = Devise.idp_entity_id_reader
|
189
|
+
Devise.idp_entity_id_reader = OurIdpEntityIdReader # which will have some different behavior
|
190
|
+
end
|
191
|
+
|
192
|
+
after do
|
193
|
+
Devise.idp_entity_id_reader = @default_reader
|
194
|
+
end
|
195
|
+
|
196
|
+
it "redirects to the associated IdP SLO target url" do
|
197
|
+
expect(controller).to receive(:sign_out)
|
198
|
+
do_delete
|
199
|
+
expect(idp_providers_adapter).to have_received(:settings).with("http://www.example.com")
|
200
|
+
expect(response).to redirect_to(%r(\Ahttp://idp_slo_url\?SAMLRequest=))
|
201
|
+
end
|
202
|
+
end
|
154
203
|
end
|
155
204
|
end
|
156
205
|
|
@@ -138,7 +138,6 @@ describe "SAML Authentication", type: :feature do
|
|
138
138
|
end
|
139
139
|
|
140
140
|
context "when the idp_settings_adapter key is set" do
|
141
|
-
|
142
141
|
before(:each) do
|
143
142
|
create_app('idp', 'INCLUDE_SUBJECT_IN_ATTRIBUTES' => "false")
|
144
143
|
create_app('sp', 'USE_SUBJECT_TO_AUTHENTICATE' => "true", 'IDP_SETTINGS_ADAPTER' => "IdpSettingsAdapter", 'IDP_ENTITY_ID_READER' => "OurEntityIdReader")
|
@@ -156,7 +155,24 @@ describe "SAML Authentication", type: :feature do
|
|
156
155
|
create_user("you@example.com")
|
157
156
|
|
158
157
|
visit 'http://localhost:8020/users/saml/sign_in/?entity_id=http%3A%2F%2Flocalhost%3A8020%2Fsaml%2Fmetadata'
|
159
|
-
expect(current_url).to match(%r(\Ahttp://www.example.com
|
158
|
+
expect(current_url).to match(%r(\Ahttp://www.example.com/sso\?SAMLRequest=))
|
159
|
+
end
|
160
|
+
|
161
|
+
it "logs a user out of the IdP via the SP" do
|
162
|
+
sign_in
|
163
|
+
|
164
|
+
# prove user is still signed in
|
165
|
+
visit 'http://localhost:8020/'
|
166
|
+
expect(page).to have_content("you@example.com")
|
167
|
+
expect(current_url).to eq("http://localhost:8020/")
|
168
|
+
|
169
|
+
click_on "Log out"
|
170
|
+
#confirm the logout response redirected to the SP which in turn attempted to sign th e
|
171
|
+
expect(current_url).to match(%r(\Ahttp://www.example.com/slo\?SAMLRequest=))
|
172
|
+
|
173
|
+
# prove user is now signed out
|
174
|
+
visit 'http://localhost:8020/users/saml/sign_in/?entity_id=http%3A%2F%2Flocalhost%3A8020%2Fsaml%2Fmetadata'
|
175
|
+
expect(current_url).to match(%r(\Ahttp://www.example.com/sso\?SAMLRequest=))
|
160
176
|
end
|
161
177
|
end
|
162
178
|
|
data/spec/support/Gemfile.rails4
CHANGED
@@ -4,7 +4,6 @@ source 'https://rubygems.org'
|
|
4
4
|
gemspec path: '../..'
|
5
5
|
|
6
6
|
group :test do
|
7
|
-
gem 'rake'
|
8
7
|
gem 'rspec', '~> 3.0'
|
9
8
|
gem 'rails', '~> 4.0'
|
10
9
|
gem 'rspec-rails'
|
@@ -16,7 +15,15 @@ group :test do
|
|
16
15
|
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.0")
|
17
16
|
gem 'addressable', '~> 2.4.0'
|
18
17
|
gem 'mime-types', '~> 2.99'
|
18
|
+
gem 'public_suffix', '~> 1.4.6'
|
19
|
+
gem 'rake', '~> 12.2.0'
|
20
|
+
elsif Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.1")
|
21
|
+
gem 'public_suffix', '~> 2.0.5'
|
22
|
+
gem 'rake'
|
23
|
+
else
|
24
|
+
gem 'rake'
|
19
25
|
end
|
26
|
+
|
20
27
|
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.1")
|
21
28
|
gem 'devise', '~> 3.5'
|
22
29
|
gem 'nokogiri', '~> 1.6.8'
|
@@ -14,11 +14,9 @@ group :test do
|
|
14
14
|
gem 'poltergeist'
|
15
15
|
|
16
16
|
# Lock down versions of gems for older versions of Ruby
|
17
|
-
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.0")
|
18
|
-
gem 'mime-types', '~> 2.99'
|
19
|
-
end
|
20
17
|
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.1")
|
21
18
|
gem 'devise', '~> 3.5'
|
19
|
+
gem 'public_suffix', '~> 2.0.5'
|
22
20
|
gem 'nokogiri', '~> 1.6.8'
|
23
21
|
end
|
24
22
|
end
|
@@ -8,8 +8,8 @@ class IdpSettingsAdapter
|
|
8
8
|
issuer: "sp_issuer",
|
9
9
|
idp_entity_id: "http://localhost:8020/saml/metadata",
|
10
10
|
authn_context: "",
|
11
|
-
idp_slo_target_url: "http://www.example.com",
|
12
|
-
idp_sso_target_url: "http://www.example.com",
|
11
|
+
idp_slo_target_url: "http://www.example.com/slo",
|
12
|
+
idp_sso_target_url: "http://www.example.com/sso",
|
13
13
|
idp_cert: "idp_cert"
|
14
14
|
}
|
15
15
|
else
|
data/spec/support/sp_template.rb
CHANGED
@@ -68,7 +68,7 @@ after_bundle do
|
|
68
68
|
insert_into_file('app/views/home/index.html.erb', after: /\z/) {
|
69
69
|
<<-HOME
|
70
70
|
<%= current_user.email %> <%= current_user.name %>
|
71
|
-
<%= form_tag destroy_user_session_path, method: :delete do %>
|
71
|
+
<%= form_tag destroy_user_session_path(entity_id: "http://localhost:8020/saml/metadata"), method: :delete do %>
|
72
72
|
<%= submit_tag "Log out" %>
|
73
73
|
<% end %>
|
74
74
|
HOME
|
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
|
+
version: 1.4.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:
|
11
|
+
date: 2018-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devise
|
@@ -85,7 +85,8 @@ files:
|
|
85
85
|
- spec/support/saml_idp_controller.rb.erb
|
86
86
|
- spec/support/sp_template.rb
|
87
87
|
homepage: ''
|
88
|
-
licenses:
|
88
|
+
licenses:
|
89
|
+
- MIT
|
89
90
|
metadata: {}
|
90
91
|
post_install_message:
|
91
92
|
rdoc_options: []
|