devise_saml_authenticatable 1.6.3 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +76 -0
- data/README.md +12 -8
- data/app/controllers/devise/saml_sessions_controller.rb +17 -2
- data/lib/devise_saml_authenticatable/strategy.rb +14 -4
- data/lib/devise_saml_authenticatable/version.rb +1 -1
- data/lib/devise_saml_authenticatable.rb +4 -0
- data/spec/controllers/devise/saml_sessions_controller_spec.rb +142 -54
- data/spec/devise_saml_authenticatable/saml_config_spec.rb +64 -17
- data/spec/devise_saml_authenticatable/strategy_spec.rb +54 -5
- data/spec/support/Gemfile.rails5.2 +1 -1
- data/spec/support/Gemfile.rails6 +14 -0
- data/spec/support/idp_settings_adapter.rb.erb +19 -9
- data/spec/support/rails_app.rb +5 -6
- data/spec/support/ruby_saml_support.rb +10 -0
- data/spec/support/sp_template.rb +15 -3
- metadata +8 -4
- data/.travis.yml +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23fdb33308c8d98c67e3fe7d5654bfcdc7afe40c2276822a3936785ed29e15ea
|
4
|
+
data.tar.gz: 11569096a198fb51b129d82eaab03a870c3c8983b7dfe88aa0bcc53f1f4fa2ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 605f76c64fa08cb1ec9f26224af74ccec6c8d85b507899e6f61f1c65e8ada6b7672b6b9398d78fcfbd075d8c7754e824e0a8ed822001b124a6658e862b72203c
|
7
|
+
data.tar.gz: 0f8bb1f715288790cffb1b20214d6c0da71c546aaa09e626183b86d1274c5d6e3aae90dea8af6c4d572c6f2131360c948203a9a14706ed7414c685833eac173d
|
@@ -0,0 +1,76 @@
|
|
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
|
+
- "2.7"
|
16
|
+
- "2.6"
|
17
|
+
- "2.5"
|
18
|
+
- "2.4"
|
19
|
+
- "2.3"
|
20
|
+
gemfile:
|
21
|
+
- Gemfile
|
22
|
+
- spec/support/Gemfile.rails6
|
23
|
+
- spec/support/Gemfile.rails5.2
|
24
|
+
- spec/support/Gemfile.rails5.1
|
25
|
+
- spec/support/Gemfile.rails5
|
26
|
+
bundler:
|
27
|
+
- "2"
|
28
|
+
exclude:
|
29
|
+
- ruby: "2.3"
|
30
|
+
gemfile: Gemfile
|
31
|
+
bundler: "2"
|
32
|
+
- ruby: "2.3"
|
33
|
+
gemfile: spec/support/Gemfile.rails6
|
34
|
+
bundler: "2"
|
35
|
+
- ruby: "2.4"
|
36
|
+
gemfile: Gemfile
|
37
|
+
bundler: "2"
|
38
|
+
- ruby: "2.4"
|
39
|
+
gemfile: spec/support/Gemfile.rails6
|
40
|
+
bundler: "2"
|
41
|
+
include:
|
42
|
+
- ruby: "2.5"
|
43
|
+
gemfile: spec/support/Gemfile.rails4
|
44
|
+
bundler: "1"
|
45
|
+
- ruby: "2.4"
|
46
|
+
gemfile: spec/support/Gemfile.rails4
|
47
|
+
bundler: "1"
|
48
|
+
- ruby: "2.3"
|
49
|
+
gemfile: spec/support/Gemfile.rails4
|
50
|
+
bundler: "1"
|
51
|
+
- ruby: "2.2"
|
52
|
+
gemfile: spec/support/Gemfile.rails5.1
|
53
|
+
bundler: "1"
|
54
|
+
- ruby: "2.2"
|
55
|
+
gemfile: spec/support/Gemfile.rails5
|
56
|
+
bundler: "1"
|
57
|
+
- ruby: "2.2"
|
58
|
+
gemfile: spec/support/Gemfile.rails4
|
59
|
+
bundler: "1"
|
60
|
+
- ruby: "2.1"
|
61
|
+
gemfile: spec/support/Gemfile.rails4
|
62
|
+
bundler: "1"
|
63
|
+
- ruby: "2.0"
|
64
|
+
gemfile: spec/support/Gemfile.rails4
|
65
|
+
bundler: "1"
|
66
|
+
runs-on: ubuntu-latest
|
67
|
+
env:
|
68
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
69
|
+
steps:
|
70
|
+
- uses: actions/checkout@v2
|
71
|
+
- uses: ruby/setup-ruby@v1
|
72
|
+
with:
|
73
|
+
bundler: ${{ matrix.bundler }}
|
74
|
+
ruby-version: ${{ matrix.ruby }}
|
75
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
76
|
+
- run: bundle exec rake
|
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 (`
|
61
|
-
- SLO endpoint (`
|
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
|
|
@@ -111,6 +111,10 @@ In `config/initializers/devise.rb`:
|
|
111
111
|
# This is a time in seconds.
|
112
112
|
# config.allowed_clock_drift_in_seconds = 0
|
113
113
|
|
114
|
+
# In SAML responses, validate that the identity provider has included an InResponseTo
|
115
|
+
# header that matches the ID of the SAML request. (Default is false)
|
116
|
+
# config.saml_validate_in_response_to = false
|
117
|
+
|
114
118
|
# Configure with your SAML settings (see ruby-saml's README for more information: https://github.com/onelogin/ruby-saml).
|
115
119
|
config.saml_configure do |settings|
|
116
120
|
# assertion_consumer_service_url is required starting with ruby-saml 1.4.3: https://github.com/onelogin/ruby-saml#updating-from-142-to-143
|
@@ -119,8 +123,8 @@ In `config/initializers/devise.rb`:
|
|
119
123
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
120
124
|
settings.issuer = "http://localhost:3000/saml/metadata"
|
121
125
|
settings.authn_context = ""
|
122
|
-
settings.
|
123
|
-
settings.
|
126
|
+
settings.idp_slo_service_url = "http://localhost/simplesaml/www/saml2/idp/SingleLogoutService.php"
|
127
|
+
settings.idp_sso_service_url = "http://localhost/simplesaml/www/saml2/idp/SSOService.php"
|
124
128
|
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
129
|
settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
|
126
130
|
end
|
@@ -207,8 +211,8 @@ class IdPSettingsAdapter
|
|
207
211
|
issuer: "http://localhost:3000/saml/metadata",
|
208
212
|
idp_entity_id: "http://www.example_idp_entity_id.com",
|
209
213
|
authn_context: "",
|
210
|
-
|
211
|
-
|
214
|
+
idp_slo_service_url: "http://example_idp_slo_service_url.com",
|
215
|
+
idp_sso_service_url: "http://example_idp_sso_service_url.com",
|
212
216
|
idp_cert: "example_idp_cert"
|
213
217
|
}
|
214
218
|
when "http://www.another_idp_entity_id.biz"
|
@@ -219,8 +223,8 @@ class IdPSettingsAdapter
|
|
219
223
|
issuer: "http://localhost:3000/saml/metadata",
|
220
224
|
idp_entity_id: "http://www.another_idp_entity_id.biz",
|
221
225
|
authn_context: "",
|
222
|
-
|
223
|
-
|
226
|
+
idp_slo_service_url: "http://another_idp_slo_service_url.com",
|
227
|
+
idp_sso_service_url: "http://another_idp_sso_service_url.com",
|
224
228
|
idp_cert: "another_idp_cert"
|
225
229
|
}
|
226
230
|
else
|
@@ -5,10 +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
|
+
prepend_before_filter :verify_signed_out_user, :store_info_for_sp_initiated_logout, only: :destroy
|
9
9
|
else
|
10
10
|
skip_before_action :verify_authenticity_token, raise: false
|
11
|
-
prepend_before_action :store_info_for_sp_initiated_logout, only: :destroy
|
11
|
+
prepend_before_action :verify_signed_out_user, :store_info_for_sp_initiated_logout, only: :destroy
|
12
12
|
end
|
13
13
|
|
14
14
|
def new
|
@@ -16,6 +16,9 @@ class Devise::SamlSessionsController < Devise::SessionsController
|
|
16
16
|
request = OneLogin::RubySaml::Authrequest.new
|
17
17
|
auth_params = { RelayState: relay_state } if relay_state
|
18
18
|
action = request.create(saml_config(idp_entity_id), auth_params || {})
|
19
|
+
if request.respond_to?(:request_id)
|
20
|
+
session[:saml_transaction_id] = request.request_id
|
21
|
+
end
|
19
22
|
redirect_to action
|
20
23
|
end
|
21
24
|
|
@@ -79,6 +82,18 @@ class Devise::SamlSessionsController < Devise::SessionsController
|
|
79
82
|
request.create(saml_settings)
|
80
83
|
end
|
81
84
|
|
85
|
+
# Overried devise: if user is signed out, not create the SP initiated logout request,
|
86
|
+
# redirect to saml_sign_out_success_url,
|
87
|
+
# or devise's after_sign_out_path_for
|
88
|
+
def verify_signed_out_user
|
89
|
+
if all_signed_out?
|
90
|
+
set_flash_message! :notice, :already_signed_out
|
91
|
+
|
92
|
+
redirect_to Devise.saml_sign_out_success_url.presence ||
|
93
|
+
Devise::SessionsController.new.after_sign_out_path_for(resource_name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
82
97
|
def generate_idp_logout_response(saml_config, logout_request_id)
|
83
98
|
|
84
99
|
params = {}
|
@@ -8,8 +8,7 @@ module Devise
|
|
8
8
|
if params[:SAMLResponse]
|
9
9
|
OneLogin::RubySaml::Response.new(
|
10
10
|
params[:SAMLResponse],
|
11
|
-
|
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
|
-
|
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(', ')}")
|
@@ -57,6 +55,18 @@ module Devise
|
|
57
55
|
Devise.saml_failed_callback.new.handle(@response, self) if Devise.saml_failed_callback
|
58
56
|
end
|
59
57
|
|
58
|
+
def response_options
|
59
|
+
options = {
|
60
|
+
settings: saml_config(get_idp_entity_id(params)),
|
61
|
+
allowed_clock_drift: Devise.allowed_clock_drift_in_seconds,
|
62
|
+
}
|
63
|
+
|
64
|
+
if Devise.saml_validate_in_response_to
|
65
|
+
options[:matches_request_id] = request.session[:saml_transaction_id] || "ID_MISSING"
|
66
|
+
end
|
67
|
+
|
68
|
+
options
|
69
|
+
end
|
60
70
|
end
|
61
71
|
end
|
62
72
|
end
|
@@ -67,6 +67,10 @@ module Devise
|
|
67
67
|
mattr_accessor :saml_relay_state
|
68
68
|
@@saml_relay_state
|
69
69
|
|
70
|
+
# Validate that the InResponseTo header in SAML responses matches the ID of the request.
|
71
|
+
mattr_accessor :saml_validate_in_response_to
|
72
|
+
@@saml_validate_in_response_to = false
|
73
|
+
|
70
74
|
# Instead of storing the attribute_map in attribute-map.yml, store it in the database, or set it programatically
|
71
75
|
mattr_accessor :saml_attribute_map_resolver
|
72
76
|
@@saml_attribute_map_resolver ||= "::DeviseSamlAuthenticatable::DefaultAttributeMapResolver"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rails_helper'
|
2
|
+
require 'support/ruby_saml_support'
|
2
3
|
|
3
4
|
# The important parts from devise
|
4
5
|
class DeviseController < ApplicationController
|
@@ -8,38 +9,55 @@ class DeviseController < ApplicationController
|
|
8
9
|
User
|
9
10
|
end
|
10
11
|
|
12
|
+
def resource_name
|
13
|
+
"users"
|
14
|
+
end
|
15
|
+
|
11
16
|
def require_no_authentication
|
12
17
|
end
|
18
|
+
|
19
|
+
def set_flash_message!(key, kind, options = {})
|
20
|
+
flash[key] = I18n.t("devise.sessions.#{kind}")
|
21
|
+
end
|
13
22
|
end
|
23
|
+
|
14
24
|
class Devise::SessionsController < DeviseController
|
15
25
|
def destroy
|
16
26
|
sign_out
|
17
27
|
redirect_to after_sign_out_path_for(:user)
|
18
28
|
end
|
19
|
-
|
20
|
-
def verify_signed_out_user
|
21
|
-
# no-op for these tests
|
22
|
-
end
|
23
29
|
end
|
24
30
|
|
25
31
|
require_relative '../../../app/controllers/devise/saml_sessions_controller'
|
26
32
|
|
27
33
|
describe Devise::SamlSessionsController, type: :controller do
|
34
|
+
include RubySamlSupport
|
35
|
+
|
28
36
|
let(:idp_providers_adapter) { spy("Stub IDPSettings Adaptor") }
|
29
37
|
|
30
38
|
before do
|
31
39
|
@request.env["devise.mapping"] = Devise.mappings[:user]
|
32
|
-
|
40
|
+
settings = {
|
33
41
|
assertion_consumer_service_url: "acs_url",
|
34
42
|
assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
|
35
43
|
name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
36
44
|
issuer: "sp_issuer",
|
37
45
|
idp_entity_id: "http://www.example.com",
|
38
46
|
authn_context: "",
|
39
|
-
idp_slo_target_url: "http://idp_slo_url",
|
40
|
-
idp_sso_target_url: "http://idp_sso_url",
|
41
47
|
idp_cert: "idp_cert"
|
48
|
+
}
|
49
|
+
with_ruby_saml_1_12_or_greater(proc {
|
50
|
+
settings.merge!(
|
51
|
+
idp_slo_service_url: "http://idp_slo_url",
|
52
|
+
idp_sso_service_url: "http://idp_sso_url",
|
53
|
+
)
|
54
|
+
}, else_do: proc {
|
55
|
+
settings.merge!(
|
56
|
+
idp_slo_target_url: "http://idp_slo_url",
|
57
|
+
idp_sso_target_url: "http://idp_sso_url",
|
58
|
+
)
|
42
59
|
})
|
60
|
+
allow(idp_providers_adapter).to receive(:settings).and_return(settings)
|
43
61
|
end
|
44
62
|
|
45
63
|
before do
|
@@ -72,6 +90,13 @@ describe Devise::SamlSessionsController, type: :controller do
|
|
72
90
|
do_get
|
73
91
|
expect(response).to redirect_to(%r(\Ahttp://localhost:8009/saml/auth\?SAMLRequest=))
|
74
92
|
end
|
93
|
+
|
94
|
+
it "stores saml_transaction_id in the session" do
|
95
|
+
do_get
|
96
|
+
if OneLogin::RubySaml::Authrequest.public_instance_methods.include?(:request_id)
|
97
|
+
expect(session[:saml_transaction_id]).to be_present
|
98
|
+
end
|
99
|
+
end
|
75
100
|
end
|
76
101
|
|
77
102
|
context "with a specified idp" do
|
@@ -84,6 +109,13 @@ describe Devise::SamlSessionsController, type: :controller do
|
|
84
109
|
expect(response).to redirect_to(%r(\Ahttp://idp_sso_url\?SAMLRequest=))
|
85
110
|
end
|
86
111
|
|
112
|
+
it "stores saml_transaction_id in the session" do
|
113
|
+
do_get
|
114
|
+
if OneLogin::RubySaml::Authrequest.public_instance_methods.include?(:request_id)
|
115
|
+
expect(session[:saml_transaction_id]).to be_present
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
87
119
|
it "uses the DefaultIdpEntityIdReader" do
|
88
120
|
expect(DeviseSamlAuthenticatable::DefaultIdpEntityIdReader).to receive(:entity_id)
|
89
121
|
do_get
|
@@ -172,80 +204,136 @@ describe Devise::SamlSessionsController, type: :controller do
|
|
172
204
|
end
|
173
205
|
|
174
206
|
describe '#destroy' do
|
175
|
-
|
176
|
-
allow(controller).to receive(:sign_out)
|
177
|
-
end
|
207
|
+
subject { delete :destroy }
|
178
208
|
|
179
|
-
context "when
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
209
|
+
context "when user is signed out" do
|
210
|
+
before do
|
211
|
+
class Devise::SessionsController < DeviseController
|
212
|
+
def all_signed_out?
|
213
|
+
true
|
214
|
+
end
|
215
|
+
end
|
184
216
|
end
|
185
|
-
end
|
186
217
|
|
187
|
-
|
188
|
-
|
189
|
-
|
218
|
+
shared_examples "not create SP initiated logout request" do
|
219
|
+
it do
|
220
|
+
expect(OneLogin::RubySaml::Logoutrequest).not_to receive(:new)
|
221
|
+
subject
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context "when Devise.saml_sign_out_success_url is set" do
|
226
|
+
before do
|
227
|
+
allow(Devise).to receive(:saml_sign_out_success_url).and_return("http://localhost:8009/logged_out")
|
228
|
+
end
|
229
|
+
|
230
|
+
it "redirect to saml_sign_out_success_url" do
|
231
|
+
is_expected.to redirect_to "http://localhost:8009/logged_out"
|
232
|
+
expect(flash[:notice]).to eq I18n.t("devise.sessions.already_signed_out")
|
233
|
+
end
|
234
|
+
|
235
|
+
it_behaves_like "not create SP initiated logout request"
|
190
236
|
end
|
191
237
|
|
192
|
-
|
193
|
-
|
238
|
+
context "when Devise.saml_sign_out_success_url is not set" do
|
239
|
+
before do
|
240
|
+
class Devise::SessionsController < DeviseController
|
241
|
+
def after_sign_out_path_for(_)
|
242
|
+
"http://localhost:8009/logged_out"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
194
246
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
"http://localhost:8009/saml/logout"
|
247
|
+
it "redirect to devise's after sign out path" do
|
248
|
+
is_expected.to redirect_to "http://localhost:8009/logged_out"
|
249
|
+
expect(flash[:notice]).to eq I18n.t("devise.sessions.already_signed_out")
|
199
250
|
end
|
200
251
|
|
201
|
-
|
202
|
-
expect(actual_settings.name_identifier_value).to eq("user@example.com")
|
203
|
-
expect(actual_settings.sessionindex).to eq("sessionindex")
|
252
|
+
it_behaves_like "not create SP initiated logout request"
|
204
253
|
end
|
205
254
|
end
|
206
255
|
|
207
|
-
context "
|
256
|
+
context "when user is not signed out" do
|
208
257
|
before do
|
209
|
-
Devise
|
258
|
+
class Devise::SessionsController < DeviseController
|
259
|
+
def all_signed_out?
|
260
|
+
false
|
261
|
+
end
|
262
|
+
end
|
263
|
+
allow(controller).to receive(:sign_out)
|
210
264
|
end
|
211
265
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
266
|
+
context "when using the default saml config" do
|
267
|
+
it "signs out and redirects to the IdP" do
|
268
|
+
delete :destroy
|
269
|
+
expect(controller).to have_received(:sign_out)
|
270
|
+
expect(response).to redirect_to(%r(\Ahttp://localhost:8009/saml/logout\?SAMLRequest=))
|
271
|
+
end
|
217
272
|
end
|
218
273
|
|
219
|
-
context "
|
220
|
-
|
221
|
-
|
222
|
-
params[:entity_id]
|
223
|
-
end
|
274
|
+
context "when configured to use a non-transient name identifier" do
|
275
|
+
before do
|
276
|
+
allow(Devise.saml_config).to receive(:name_identifier_format).and_return("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent")
|
224
277
|
end
|
225
278
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
279
|
+
it "includes a LogoutRequest with the name identifier and session index", :aggregate_failures do
|
280
|
+
controller.current_user = Struct.new(:email, :session_index).new("user@example.com", "sessionindex")
|
281
|
+
|
282
|
+
actual_settings = nil
|
283
|
+
expect_any_instance_of(OneLogin::RubySaml::Logoutrequest).to receive(:create) do |_, settings|
|
284
|
+
actual_settings = settings
|
285
|
+
"http://localhost:8009/saml/logout"
|
231
286
|
end
|
232
|
-
}
|
233
287
|
|
234
|
-
|
235
|
-
@
|
236
|
-
|
288
|
+
delete :destroy
|
289
|
+
expect(actual_settings.name_identifier_value).to eq("user@example.com")
|
290
|
+
expect(actual_settings.sessionindex).to eq("sessionindex")
|
237
291
|
end
|
292
|
+
end
|
238
293
|
|
239
|
-
|
240
|
-
|
294
|
+
context "with a specified idp" do
|
295
|
+
before do
|
296
|
+
Devise.idp_settings_adapter = idp_providers_adapter
|
241
297
|
end
|
242
298
|
|
243
|
-
it "redirects to the associated IdP
|
244
|
-
|
299
|
+
it "redirects to the associated IdP SSO target url" do
|
300
|
+
expect(DeviseSamlAuthenticatable::DefaultIdpEntityIdReader).to receive(:entity_id)
|
301
|
+
delete :destroy
|
245
302
|
expect(controller).to have_received(:sign_out)
|
246
|
-
expect(idp_providers_adapter).to have_received(:settings).with("http://www.example.com")
|
247
303
|
expect(response).to redirect_to(%r(\Ahttp://idp_slo_url\?SAMLRequest=))
|
248
304
|
end
|
305
|
+
|
306
|
+
context "with a specified idp entity id reader" do
|
307
|
+
class OurIdpEntityIdReader
|
308
|
+
def self.entity_id(params)
|
309
|
+
params[:entity_id]
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
subject(:do_delete) {
|
314
|
+
if Rails::VERSION::MAJOR > 4
|
315
|
+
delete :destroy, params: {entity_id: "http://www.example.com"}
|
316
|
+
else
|
317
|
+
delete :destroy, entity_id: "http://www.example.com"
|
318
|
+
end
|
319
|
+
}
|
320
|
+
|
321
|
+
before do
|
322
|
+
@default_reader = Devise.idp_entity_id_reader
|
323
|
+
Devise.idp_entity_id_reader = OurIdpEntityIdReader # which will have some different behavior
|
324
|
+
end
|
325
|
+
|
326
|
+
after do
|
327
|
+
Devise.idp_entity_id_reader = @default_reader
|
328
|
+
end
|
329
|
+
|
330
|
+
it "redirects to the associated IdP SLO target url" do
|
331
|
+
do_delete
|
332
|
+
expect(controller).to have_received(:sign_out)
|
333
|
+
expect(idp_providers_adapter).to have_received(:settings).with("http://www.example.com")
|
334
|
+
expect(response).to redirect_to(%r(\Ahttp://idp_slo_url\?SAMLRequest=))
|
335
|
+
end
|
336
|
+
end
|
249
337
|
end
|
250
338
|
end
|
251
339
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'support/ruby_saml_support'
|
2
3
|
|
3
4
|
describe DeviseSamlAuthenticatable::SamlConfig do
|
5
|
+
include RubySamlSupport
|
6
|
+
|
4
7
|
let(:saml_config) { controller.saml_config }
|
5
8
|
let(:controller) { Class.new { include DeviseSamlAuthenticatable::SamlConfig }.new }
|
6
9
|
|
@@ -26,32 +29,54 @@ describe DeviseSamlAuthenticatable::SamlConfig do
|
|
26
29
|
let(:saml_config) { controller.saml_config(idp_entity_id) }
|
27
30
|
let(:idp_providers_adapter) {
|
28
31
|
Class.new {
|
32
|
+
extend RubySamlSupport
|
33
|
+
|
29
34
|
def self.settings(idp_entity_id)
|
30
35
|
#some hash of stuff (by doing a fetch, in our case, but could also be a giant hash keyed by idp_entity_id)
|
31
36
|
if idp_entity_id == "http://www.example.com"
|
32
|
-
{
|
37
|
+
base = {
|
33
38
|
assertion_consumer_service_url: "acs_url",
|
34
39
|
assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
|
35
40
|
name_identifier_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
36
41
|
issuer: "sp_issuer",
|
37
42
|
idp_entity_id: "http://www.example.com",
|
38
43
|
authn_context: "",
|
39
|
-
idp_slo_target_url: "idp_slo_url",
|
40
|
-
idp_sso_target_url: "idp_sso_url",
|
41
44
|
idp_cert: "idp_cert"
|
42
45
|
}
|
46
|
+
with_ruby_saml_1_12_or_greater(proc {
|
47
|
+
base.merge!(
|
48
|
+
idp_slo_service_url: "idp_slo_url",
|
49
|
+
idp_sso_service_url: "idp_sso_url",
|
50
|
+
)
|
51
|
+
}, else_do: proc {
|
52
|
+
base.merge!(
|
53
|
+
idp_slo_target_url: "idp_slo_url",
|
54
|
+
idp_sso_target_url: "idp_sso_url",
|
55
|
+
)
|
56
|
+
})
|
57
|
+
base
|
43
58
|
elsif idp_entity_id == "http://www.example.com_other"
|
44
|
-
{
|
59
|
+
base = {
|
45
60
|
assertion_consumer_service_url: "acs_url_other",
|
46
61
|
assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST_other",
|
47
62
|
name_identifier_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress_other",
|
48
63
|
issuer: "sp_issuer_other",
|
49
64
|
idp_entity_id: "http://www.example.com_other",
|
50
65
|
authn_context: "_other",
|
51
|
-
idp_slo_target_url: "idp_slo_url_other",
|
52
|
-
idp_sso_target_url: "idp_sso_url_other",
|
53
66
|
idp_cert: "idp_cert_other"
|
54
67
|
}
|
68
|
+
with_ruby_saml_1_12_or_greater(proc {
|
69
|
+
base.merge!(
|
70
|
+
idp_slo_service_url: "idp_slo_url_other",
|
71
|
+
idp_sso_service_url: "idp_sso_url_other",
|
72
|
+
)
|
73
|
+
}, else_do: proc {
|
74
|
+
base.merge!(
|
75
|
+
idp_slo_target_url: "idp_slo_url_other",
|
76
|
+
idp_sso_target_url: "idp_sso_url_other",
|
77
|
+
)
|
78
|
+
})
|
79
|
+
base
|
55
80
|
else
|
56
81
|
{}
|
57
82
|
end
|
@@ -63,7 +88,11 @@ describe DeviseSamlAuthenticatable::SamlConfig do
|
|
63
88
|
let(:idp_entity_id) { "http://www.example.com" }
|
64
89
|
it "uses the settings from the adapter for that idp" do
|
65
90
|
expect(saml_config.idp_entity_id).to eq (idp_entity_id)
|
66
|
-
|
91
|
+
with_ruby_saml_1_12_or_greater(proc {
|
92
|
+
expect(saml_config.idp_sso_service_url).to eq('idp_sso_url')
|
93
|
+
}, else_do: proc {
|
94
|
+
expect(saml_config.idp_sso_target_url).to eq('idp_sso_url')
|
95
|
+
})
|
67
96
|
expect(saml_config.class).to eq OneLogin::RubySaml::Settings
|
68
97
|
end
|
69
98
|
end
|
@@ -72,7 +101,11 @@ describe DeviseSamlAuthenticatable::SamlConfig do
|
|
72
101
|
let(:idp_entity_id) { "http://www.example.com_other" }
|
73
102
|
it "returns the other idp settings" do
|
74
103
|
expect(saml_config.idp_entity_id).to eq (idp_entity_id)
|
75
|
-
|
104
|
+
with_ruby_saml_1_12_or_greater(proc {
|
105
|
+
expect(saml_config.idp_sso_service_url).to eq('idp_sso_url_other')
|
106
|
+
}, else_do: proc {
|
107
|
+
expect(saml_config.idp_sso_target_url).to eq('idp_sso_url_other')
|
108
|
+
})
|
76
109
|
expect(saml_config.class).to eq OneLogin::RubySaml::Settings
|
77
110
|
end
|
78
111
|
end
|
@@ -80,11 +113,8 @@ describe DeviseSamlAuthenticatable::SamlConfig do
|
|
80
113
|
end
|
81
114
|
|
82
115
|
context "when config/idp.yml exists" do
|
83
|
-
|
84
|
-
|
85
|
-
allow(Rails).to receive(:root).and_return("/railsroot")
|
86
|
-
allow(File).to receive(:exists?).with("/railsroot/config/idp.yml").and_return(true)
|
87
|
-
allow(File).to receive(:read).with("/railsroot/config/idp.yml").and_return(<<-IDP)
|
116
|
+
let(:idp_yaml) {
|
117
|
+
yaml = <<-IDP
|
88
118
|
---
|
89
119
|
environment:
|
90
120
|
assertion_consumer_logout_service_binding: assertion_consumer_logout_service_binding
|
@@ -104,8 +134,6 @@ environment:
|
|
104
134
|
idp_cert_fingerprint: idp_cert_fingerprint
|
105
135
|
idp_cert_fingerprint_algorithm: idp_cert_fingerprint_algorithm
|
106
136
|
idp_entity_id: idp_entity_id
|
107
|
-
idp_slo_target_url: idp_slo_target_url
|
108
|
-
idp_sso_target_url: idp_sso_target_url
|
109
137
|
issuer: issuer
|
110
138
|
name_identifier_format: name_identifier_format
|
111
139
|
name_identifier_value: name_identifier_value
|
@@ -116,6 +144,20 @@ environment:
|
|
116
144
|
sessionindex: sessionindex
|
117
145
|
sp_name_qualifier: sp_name_qualifier
|
118
146
|
IDP
|
147
|
+
with_ruby_saml_1_12_or_greater(proc { yaml << <<SERVICE_URLS }, else_do: proc { yaml << <<TARGET_URLS })
|
148
|
+
idp_slo_service_url: idp_slo_service_url
|
149
|
+
idp_sso_service_url: idp_sso_service_url
|
150
|
+
SERVICE_URLS
|
151
|
+
idp_slo_target_url: idp_slo_service_url
|
152
|
+
idp_sso_target_url: idp_sso_service_url
|
153
|
+
TARGET_URLS
|
154
|
+
yaml
|
155
|
+
}
|
156
|
+
before do
|
157
|
+
allow(Rails).to receive(:env).and_return("environment")
|
158
|
+
allow(Rails).to receive(:root).and_return("/railsroot")
|
159
|
+
allow(File).to receive(:exists?).with("/railsroot/config/idp.yml").and_return(true)
|
160
|
+
allow(File).to receive(:read).with("/railsroot/config/idp.yml").and_return(idp_yaml)
|
119
161
|
end
|
120
162
|
|
121
163
|
it "uses that file's contents" do
|
@@ -136,8 +178,13 @@ environment:
|
|
136
178
|
expect(saml_config.idp_cert_fingerprint).to eq('idp_cert_fingerprint')
|
137
179
|
expect(saml_config.idp_cert_fingerprint_algorithm).to eq('idp_cert_fingerprint_algorithm')
|
138
180
|
expect(saml_config.idp_entity_id).to eq('idp_entity_id')
|
139
|
-
|
140
|
-
|
181
|
+
with_ruby_saml_1_12_or_greater(proc {
|
182
|
+
expect(saml_config.idp_slo_service_url).to eq('idp_slo_service_url')
|
183
|
+
expect(saml_config.idp_sso_service_url).to eq('idp_sso_service_url')
|
184
|
+
}, else_do: proc {
|
185
|
+
expect(saml_config.idp_slo_target_url).to eq('idp_slo_service_url')
|
186
|
+
expect(saml_config.idp_sso_target_url).to eq('idp_sso_service_url')
|
187
|
+
})
|
141
188
|
expect(saml_config.issuer).to eq('issuer')
|
142
189
|
expect(saml_config.name_identifier_format).to eq('name_identifier_format')
|
143
190
|
expect(saml_config.name_identifier_value).to eq('name_identifier_value')
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'rails_helper'
|
2
|
+
require 'support/ruby_saml_support'
|
2
3
|
|
3
4
|
describe Devise::Strategies::SamlAuthenticatable do
|
5
|
+
include RubySamlSupport
|
6
|
+
|
4
7
|
subject(:strategy) { described_class.new(env, :user) }
|
5
8
|
let(:env) { {} }
|
6
9
|
let(:errors) { ["Test1", "Test2"] }
|
@@ -16,7 +19,7 @@ describe Devise::Strategies::SamlAuthenticatable do
|
|
16
19
|
let(:user) { double(:user) }
|
17
20
|
before do
|
18
21
|
allow(strategy).to receive(:mapping).and_return(mapping)
|
19
|
-
allow(user).to
|
22
|
+
allow(user).to(receive(:after_saml_authentication)) if user
|
20
23
|
end
|
21
24
|
|
22
25
|
let(:params) { {} }
|
@@ -54,17 +57,27 @@ describe Devise::Strategies::SamlAuthenticatable do
|
|
54
57
|
let(:idp_providers_adapter) {
|
55
58
|
Class.new {
|
56
59
|
def self.settings(idp_entity_id)
|
57
|
-
{
|
60
|
+
base = {
|
58
61
|
assertion_consumer_service_url: "acs_url",
|
59
62
|
assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
|
60
63
|
name_identifier_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
61
64
|
issuer: "sp_issuer",
|
62
65
|
idp_entity_id: "http://www.example.com",
|
63
66
|
authn_context: "",
|
64
|
-
idp_slo_target_url: "idp_slo_url",
|
65
|
-
idp_sso_target_url: "http://idp_sso_url",
|
66
67
|
idp_cert: "idp_cert"
|
67
68
|
}
|
69
|
+
with_ruby_saml_1_12_or_greater(proc {
|
70
|
+
base.merge!(
|
71
|
+
idp_slo_service_url: "idp_slo_url",
|
72
|
+
idp_sso_service_url: "http://idp_sso_url",
|
73
|
+
)
|
74
|
+
}, else_do: proc {
|
75
|
+
base.merge!(
|
76
|
+
idp_slo_target_url: "idp_slo_url",
|
77
|
+
idp_sso_target_url: "http://idp_sso_url",
|
78
|
+
)
|
79
|
+
})
|
80
|
+
base
|
68
81
|
end
|
69
82
|
}
|
70
83
|
}
|
@@ -93,8 +106,10 @@ describe Devise::Strategies::SamlAuthenticatable do
|
|
93
106
|
let(:user) { nil }
|
94
107
|
|
95
108
|
it "fails to authenticate" do
|
96
|
-
expect(strategy).to receive(:fail!).with(:invalid)
|
97
109
|
strategy.authenticate!
|
110
|
+
expect(strategy).to be_halted
|
111
|
+
expect(strategy.message).to be(:invalid)
|
112
|
+
expect(strategy.result).to be(:failure)
|
98
113
|
end
|
99
114
|
|
100
115
|
it 'logs the error' do
|
@@ -152,6 +167,40 @@ describe Devise::Strategies::SamlAuthenticatable do
|
|
152
167
|
strategy.authenticate!
|
153
168
|
end
|
154
169
|
end
|
170
|
+
|
171
|
+
context "when saml_validate_in_response_to is opted-in to" do
|
172
|
+
let(:transaction_id) { "abc123" }
|
173
|
+
|
174
|
+
before do
|
175
|
+
allow(Devise).to receive(:saml_validate_in_response_to).and_return(true)
|
176
|
+
allow_any_instance_of(ActionDispatch::Request).to receive(:session).and_return(session)
|
177
|
+
end
|
178
|
+
|
179
|
+
context "when the session has a saml_transaction_id" do
|
180
|
+
let(:session) { { saml_transaction_id: transaction_id }}
|
181
|
+
|
182
|
+
it "is valid with the matches_request_id parameter" do
|
183
|
+
expect(OneLogin::RubySaml::Response).to receive(:new).with(params[:SAMLResponse], hash_including(matches_request_id: transaction_id))
|
184
|
+
expect(strategy).to be_valid
|
185
|
+
end
|
186
|
+
|
187
|
+
it "authenticates with the matches_request_id parameter" do
|
188
|
+
expect(OneLogin::RubySaml::Response).to receive(:new).with(params[:SAMLResponse], hash_including(matches_request_id: transaction_id))
|
189
|
+
|
190
|
+
expect(strategy).to receive(:success!).with(user)
|
191
|
+
strategy.authenticate!
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context "when the session is missing a saml_transaction_id" do
|
196
|
+
let(:session) { { } }
|
197
|
+
|
198
|
+
it "uses 'ID_MISSING' for matches_request_id so validation will fail" do
|
199
|
+
expect(OneLogin::RubySaml::Response).to receive(:new).with(params[:SAMLResponse], hash_including(matches_request_id: "ID_MISSING"))
|
200
|
+
strategy.authenticate!
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
155
204
|
end
|
156
205
|
|
157
206
|
it "is not valid without a SAMLResponse parameter" do
|
@@ -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', '~> 6.0.0'
|
10
|
+
gem 'rspec-rails', '~> 5.0'
|
11
|
+
gem 'sqlite3', '~> 1.4.0'
|
12
|
+
gem 'capybara'
|
13
|
+
gem 'poltergeist'
|
14
|
+
end
|
@@ -1,17 +1,27 @@
|
|
1
1
|
class IdpSettingsAdapter
|
2
2
|
def self.settings(idp_entity_id)
|
3
3
|
if idp_entity_id == "http://localhost:8020/saml/metadata"
|
4
|
-
{
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
base = {
|
5
|
+
assertion_consumer_service_url: "http://localhost:8020/users/saml/auth",
|
6
|
+
assertion_consumer_service_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
|
7
|
+
name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
8
|
+
issuer: "sp_issuer",
|
9
|
+
idp_entity_id: "http://localhost:8020/saml/metadata",
|
10
|
+
authn_context: "",
|
11
|
+
idp_cert_fingerprint: "9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D"
|
12
|
+
}
|
13
|
+
if Gem::Version.new(OneLogin::RubySaml::VERSION) >= Gem::Version.new("1.12.0")
|
14
|
+
base.merge!(
|
15
|
+
idp_slo_service_url: "http://localhost:8010/saml/logout",
|
16
|
+
idp_sso_service_url: "http://localhost:8010/saml/auth",
|
17
|
+
)
|
18
|
+
else
|
19
|
+
base.merge!(
|
11
20
|
idp_slo_target_url: "http://localhost:8010/saml/logout",
|
12
21
|
idp_sso_target_url: "http://localhost:8010/saml/auth",
|
13
|
-
|
14
|
-
|
22
|
+
)
|
23
|
+
end
|
24
|
+
base
|
15
25
|
else
|
16
26
|
{}
|
17
27
|
end
|
data/spec/support/rails_app.rb
CHANGED
@@ -21,12 +21,11 @@ def create_app(name, env = {})
|
|
21
21
|
puts "[#{name}] Creating Rails app"
|
22
22
|
rails_new_options = %w[-T -J -S --skip-spring --skip-listen --skip-bootsnap]
|
23
23
|
rails_new_options << "-O" if name == "idp"
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
24
|
+
env.merge!("RUBY_SAML_VERSION" => OneLogin::RubySaml::VERSION)
|
25
|
+
Dir.chdir(working_directory) do
|
26
|
+
FileUtils.rm_rf(name)
|
27
|
+
puts("[#{working_directory}] rails _#{Rails.version}_ new #{name} #{rails_new_options.join(" ")} -m #{File.expand_path("../#{name}_template.rb", __FILE__)}")
|
28
|
+
system(env, "rails", "_#{Rails.version}_", "new", name, *rails_new_options, "-m", File.expand_path("../#{name}_template.rb", __FILE__))
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
data/spec/support/sp_template.rb
CHANGED
@@ -8,13 +8,14 @@ use_subject_to_authenticate = ENV.fetch('USE_SUBJECT_TO_AUTHENTICATE')
|
|
8
8
|
idp_settings_adapter = ENV.fetch('IDP_SETTINGS_ADAPTER', "nil")
|
9
9
|
idp_entity_id_reader = ENV.fetch('IDP_ENTITY_ID_READER', '"DeviseSamlAuthenticatable::DefaultIdpEntityIdReader"')
|
10
10
|
saml_failed_callback = ENV.fetch('SAML_FAILED_CALLBACK', "nil")
|
11
|
+
ruby_saml_version = ENV.fetch("RUBY_SAML_VERSION")
|
11
12
|
|
12
13
|
if Rails::VERSION::MAJOR < 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR < 2)
|
13
14
|
gsub_file 'config/secrets.yml', /secret_key_base:.*$/, 'secret_key_base: "8b5889df1fcf03f76c7d66da02d8776bcc85b06bed7d9c592f076d9c8a5455ee6d4beae45986c3c030b40208db5e612f2a6ef8283036a352e3fae83c5eda36be"'
|
14
15
|
end
|
15
16
|
|
16
17
|
gem 'devise_saml_authenticatable', path: File.expand_path("../../..", __FILE__)
|
17
|
-
gem 'ruby-saml',
|
18
|
+
gem 'ruby-saml', ruby_saml_version
|
18
19
|
gem 'thin'
|
19
20
|
|
20
21
|
insert_into_file('Gemfile', after: /\z/) {
|
@@ -92,13 +93,24 @@ after_bundle do
|
|
92
93
|
config.saml_configure do |settings|
|
93
94
|
settings.assertion_consumer_service_url = "http://localhost:8020/users/saml/auth"
|
94
95
|
settings.issuer = "http://localhost:8020/saml/metadata"
|
95
|
-
settings.idp_slo_target_url = "http://localhost:8009/saml/logout"
|
96
|
-
settings.idp_sso_target_url = "http://localhost:8009/saml/auth"
|
97
96
|
settings.idp_cert_fingerprint = "9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D"
|
98
97
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
99
98
|
end
|
100
99
|
end
|
101
100
|
CONFIG
|
101
|
+
if Gem::Version.new(ruby_saml_version) >= Gem::Version.new("1.12.0")
|
102
|
+
gsub_file 'config/initializers/devise.rb', /^ config\.saml_configure do \|settings\|$/, <<CONFIG
|
103
|
+
config.saml_configure do |settings|
|
104
|
+
settings.idp_slo_service_url = "http://localhost:8009/saml/logout"
|
105
|
+
settings.idp_sso_service_url = "http://localhost:8009/saml/auth"
|
106
|
+
CONFIG
|
107
|
+
else
|
108
|
+
gsub_file 'config/initializers/devise.rb', /^ config\.saml_configure do \|settings\|$/, <<CONFIG
|
109
|
+
config.saml_configure do |settings|
|
110
|
+
settings.idp_slo_target_url = "http://localhost:8009/saml/logout"
|
111
|
+
settings.idp_sso_target_url = "http://localhost:8009/saml/auth"
|
112
|
+
CONFIG
|
113
|
+
end
|
102
114
|
|
103
115
|
generate :controller, 'home', 'index'
|
104
116
|
insert_into_file('app/controllers/home_controller.rb', after: "class HomeController < ApplicationController\n") {
|
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.7.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: 2021-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devise
|
@@ -45,9 +45,9 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- ".github/workflows/ci.yml"
|
48
49
|
- ".gitignore"
|
49
50
|
- ".rspec"
|
50
|
-
- ".travis.yml"
|
51
51
|
- Gemfile
|
52
52
|
- LICENSE
|
53
53
|
- README.md
|
@@ -82,12 +82,14 @@ files:
|
|
82
82
|
- spec/support/Gemfile.rails5
|
83
83
|
- spec/support/Gemfile.rails5.1
|
84
84
|
- spec/support/Gemfile.rails5.2
|
85
|
+
- spec/support/Gemfile.rails6
|
85
86
|
- spec/support/attribute-map.yml
|
86
87
|
- spec/support/attribute_map_resolver.rb.erb
|
87
88
|
- spec/support/idp_settings_adapter.rb.erb
|
88
89
|
- spec/support/idp_template.rb
|
89
90
|
- spec/support/rails_app.rb
|
90
91
|
- spec/support/response_encrypted_nameid.xml.base64
|
92
|
+
- spec/support/ruby_saml_support.rb
|
91
93
|
- spec/support/saml_idp-saml_slo_post.html.erb
|
92
94
|
- spec/support/saml_idp_controller.rb.erb
|
93
95
|
- spec/support/sp_template.rb
|
@@ -110,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
112
|
- !ruby/object:Gem::Version
|
111
113
|
version: '0'
|
112
114
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
115
|
+
rubygems_version: 3.1.4
|
114
116
|
signing_key:
|
115
117
|
specification_version: 4
|
116
118
|
summary: SAML Authentication for devise
|
@@ -130,12 +132,14 @@ test_files:
|
|
130
132
|
- spec/support/Gemfile.rails5
|
131
133
|
- spec/support/Gemfile.rails5.1
|
132
134
|
- spec/support/Gemfile.rails5.2
|
135
|
+
- spec/support/Gemfile.rails6
|
133
136
|
- spec/support/attribute-map.yml
|
134
137
|
- spec/support/attribute_map_resolver.rb.erb
|
135
138
|
- spec/support/idp_settings_adapter.rb.erb
|
136
139
|
- spec/support/idp_template.rb
|
137
140
|
- spec/support/rails_app.rb
|
138
141
|
- spec/support/response_encrypted_nameid.xml.base64
|
142
|
+
- spec/support/ruby_saml_support.rb
|
139
143
|
- spec/support/saml_idp-saml_slo_post.html.erb
|
140
144
|
- spec/support/saml_idp_controller.rb.erb
|
141
145
|
- spec/support/sp_template.rb
|
data/.travis.yml
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- "2.0.0"
|
4
|
-
- "2.1.10"
|
5
|
-
- "2.2.10"
|
6
|
-
- "2.3.8"
|
7
|
-
- "2.4.10"
|
8
|
-
- "2.5.8"
|
9
|
-
- "2.6.6"
|
10
|
-
- "2.7.1"
|
11
|
-
gemfile:
|
12
|
-
- Gemfile
|
13
|
-
- spec/support/Gemfile.rails5.2
|
14
|
-
- spec/support/Gemfile.rails5.1
|
15
|
-
- spec/support/Gemfile.rails5
|
16
|
-
- spec/support/Gemfile.rails4
|
17
|
-
matrix:
|
18
|
-
allow_failures:
|
19
|
-
- rvm: "2.0.0"
|
20
|
-
gemfile: Gemfile
|
21
|
-
- rvm: "2.0.0"
|
22
|
-
gemfile: spec/support/Gemfile.rails5
|
23
|
-
- rvm: "2.0.0"
|
24
|
-
gemfile: spec/support/Gemfile.rails5.1
|
25
|
-
- rvm: "2.0.0"
|
26
|
-
gemfile: spec/support/Gemfile.rails5.2
|
27
|
-
- rvm: "2.1.10"
|
28
|
-
gemfile: Gemfile
|
29
|
-
- rvm: "2.1.10"
|
30
|
-
gemfile: spec/support/Gemfile.rails5
|
31
|
-
- rvm: "2.1.10"
|
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
|
47
|
-
|
48
|
-
before_install:
|
49
|
-
- command -v bundle || gem install bundler -v '~> 1.17.3'
|
50
|
-
|
51
|
-
script:
|
52
|
-
- bundle exec rake
|