devise_saml_authenticatable 1.6.1 → 1.8.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/.github/workflows/ci.yml +52 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +12 -2
- data/README.md +22 -19
- data/app/controllers/devise/saml_sessions_controller.rb +27 -21
- data/lib/devise_saml_authenticatable/logger.rb +2 -2
- data/lib/devise_saml_authenticatable/model.rb +10 -7
- data/lib/devise_saml_authenticatable/saml_config.rb +18 -2
- data/lib/devise_saml_authenticatable/strategy.rb +23 -5
- data/lib/devise_saml_authenticatable/version.rb +1 -1
- data/lib/devise_saml_authenticatable.rb +6 -2
- data/spec/controllers/devise/saml_sessions_controller_spec.rb +203 -145
- data/spec/devise_saml_authenticatable/model_spec.rb +0 -13
- data/spec/devise_saml_authenticatable/saml_config_spec.rb +64 -17
- data/spec/devise_saml_authenticatable/strategy_spec.rb +54 -5
- data/spec/features/saml_authentication_spec.rb +19 -6
- data/spec/support/Gemfile.rails5.2 +2 -13
- data/spec/support/Gemfile.rails6 +18 -0
- data/spec/support/Gemfile.rails6.1 +24 -0
- data/spec/support/idp_settings_adapter.rb.erb +19 -9
- data/spec/support/idp_template.rb +5 -13
- data/spec/support/rails_app.rb +6 -7
- data/spec/support/ruby_saml_support.rb +10 -0
- data/spec/support/saml_idp_controller.rb.erb +1 -6
- data/spec/support/sp_template.rb +21 -18
- metadata +11 -10
- data/.travis.yml +0 -52
- data/spec/support/Gemfile.rails4 +0 -41
- data/spec/support/Gemfile.rails5 +0 -25
- data/spec/support/Gemfile.rails5.1 +0 -25
@@ -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
|
@@ -3,8 +3,21 @@ require 'net/http'
|
|
3
3
|
require 'timeout'
|
4
4
|
require 'uri'
|
5
5
|
require 'capybara/rspec'
|
6
|
-
require '
|
7
|
-
|
6
|
+
require 'selenium-webdriver'
|
7
|
+
|
8
|
+
Capybara.register_driver :chrome do |app|
|
9
|
+
options = Selenium::WebDriver::Chrome::Options.new
|
10
|
+
options.add_argument('--headless')
|
11
|
+
options.add_argument('--allow-insecure-localhost')
|
12
|
+
options.add_argument('--ignore-certificate-errors')
|
13
|
+
|
14
|
+
Capybara::Selenium::Driver.new(
|
15
|
+
app,
|
16
|
+
browser: :chrome,
|
17
|
+
capabilities: [options]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
Capybara.default_driver = :chrome
|
8
21
|
Capybara.server = :webrick
|
9
22
|
|
10
23
|
describe "SAML Authentication", type: :feature do
|
@@ -141,7 +154,7 @@ describe "SAML Authentication", type: :feature do
|
|
141
154
|
context "when the idp_settings_adapter key is set" do
|
142
155
|
before(:each) do
|
143
156
|
create_app('idp', 'INCLUDE_SUBJECT_IN_ATTRIBUTES' => "false")
|
144
|
-
create_app('sp', 'USE_SUBJECT_TO_AUTHENTICATE' => "true", 'IDP_SETTINGS_ADAPTER' => "IdpSettingsAdapter", 'IDP_ENTITY_ID_READER' => "OurEntityIdReader")
|
157
|
+
create_app('sp', 'USE_SUBJECT_TO_AUTHENTICATE' => "true", 'IDP_SETTINGS_ADAPTER' => '"IdpSettingsAdapter"', 'IDP_ENTITY_ID_READER' => '"OurEntityIdReader"')
|
145
158
|
|
146
159
|
# use a different port for this entity ID; configured in spec/support/idp_settings_adapter.rb.erb
|
147
160
|
@idp_pid = start_app('idp', 8010)
|
@@ -165,7 +178,7 @@ describe "SAML Authentication", type: :feature do
|
|
165
178
|
let(:valid_destination) { "true" }
|
166
179
|
before(:each) do
|
167
180
|
create_app('idp', 'INCLUDE_SUBJECT_IN_ATTRIBUTES' => "false", 'VALID_DESTINATION' => valid_destination)
|
168
|
-
create_app('sp', 'USE_SUBJECT_TO_AUTHENTICATE' => "true", 'SAML_FAILED_CALLBACK' => "OurSamlFailedCallbackHandler")
|
181
|
+
create_app('sp', 'USE_SUBJECT_TO_AUTHENTICATE' => "true", 'SAML_FAILED_CALLBACK' => '"OurSamlFailedCallbackHandler"')
|
169
182
|
|
170
183
|
@idp_pid = start_app('idp', idp_port)
|
171
184
|
@sp_pid = start_app('sp', sp_port)
|
@@ -204,7 +217,7 @@ describe "SAML Authentication", type: :feature do
|
|
204
217
|
)
|
205
218
|
create_app(
|
206
219
|
"sp",
|
207
|
-
"ATTRIBUTE_MAP_RESOLVER" => "AttributeMapResolver",
|
220
|
+
"ATTRIBUTE_MAP_RESOLVER" => '"AttributeMapResolver"',
|
208
221
|
"USE_SUBJECT_TO_AUTHENTICATE" => "true",
|
209
222
|
)
|
210
223
|
@idp_pid = start_app("idp", idp_port)
|
@@ -224,7 +237,7 @@ describe "SAML Authentication", type: :feature do
|
|
224
237
|
end
|
225
238
|
|
226
239
|
def sign_in(entity_id: "")
|
227
|
-
visit "http://localhost:8020/users/saml/sign_in/?entity_id=#{URI.
|
240
|
+
visit "http://localhost:8020/users/saml/sign_in/?entity_id=#{URI.encode_www_form_component(entity_id)}"
|
228
241
|
fill_in "Email", with: "you@example.com"
|
229
242
|
fill_in "Password", with: "asdf"
|
230
243
|
click_on "Sign in"
|
@@ -6,20 +6,9 @@ gemspec path: '../..'
|
|
6
6
|
group :test do
|
7
7
|
gem 'rake'
|
8
8
|
gem 'rspec', '~> 3.0'
|
9
|
-
gem 'rails', '~> 5.2'
|
9
|
+
gem 'rails', '~> 5.2.0'
|
10
10
|
gem 'rspec-rails', '~> 3.9'
|
11
11
|
gem 'sqlite3', '~> 1.3.6'
|
12
12
|
gem 'capybara'
|
13
|
-
gem '
|
14
|
-
|
15
|
-
# Lock down versions of gems for older versions of Ruby
|
16
|
-
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.4")
|
17
|
-
gem 'responders', '~> 2.4'
|
18
|
-
end
|
19
|
-
|
20
|
-
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.3")
|
21
|
-
gem 'byebug', '~> 10.0'
|
22
|
-
elsif Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.4")
|
23
|
-
gem 'byebug', '~> 11.0.0'
|
24
|
-
end
|
13
|
+
gem 'selenium-webdriver'
|
25
14
|
end
|
@@ -0,0 +1,18 @@
|
|
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 'selenium-webdriver'
|
14
|
+
|
15
|
+
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new("3.0")
|
16
|
+
gem 'webrick'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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.1.0'
|
10
|
+
gem 'rspec-rails', '~> 5.0'
|
11
|
+
gem 'sqlite3', '~> 1.4.0'
|
12
|
+
gem 'capybara'
|
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
|
24
|
+
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
|
@@ -5,22 +5,14 @@
|
|
5
5
|
@include_subject_in_attributes = ENV.fetch('INCLUDE_SUBJECT_IN_ATTRIBUTES')
|
6
6
|
@valid_destination = ENV.fetch('VALID_DESTINATION', "true")
|
7
7
|
|
8
|
-
|
9
|
-
gsub_file 'config/secrets.yml', /secret_key_base:.*$/, 'secret_key_base: "34814fd41f91c493b89aa01ac73c44d241a31245b5bc5542fa4b7317525e1dcfa60ba947b3d085e4e229456fdee0d8af6aac6a63cf750d807ea6fe5d853dff4a"'
|
10
|
-
end
|
11
|
-
|
12
|
-
gem 'ruby-saml-idp', '~> 0.3.3'
|
8
|
+
gem 'stub_saml_idp'
|
13
9
|
gem 'thin'
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
gem 'devise', '~> 3.5'
|
20
|
-
gem 'nokogiri', '~> 1.6.8'
|
11
|
+
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new("3.1")
|
12
|
+
gem 'net-smtp', require: false
|
13
|
+
gem 'net-imap', require: false
|
14
|
+
gem 'net-pop', require: false
|
21
15
|
end
|
22
|
-
GEMFILE
|
23
|
-
}
|
24
16
|
|
25
17
|
route "get '/saml/auth' => 'saml_idp#new'"
|
26
18
|
route "post '/saml/auth' => 'saml_idp#create'"
|
data/spec/support/rails_app.rb
CHANGED
@@ -19,14 +19,13 @@ end
|
|
19
19
|
|
20
20
|
def create_app(name, env = {})
|
21
21
|
puts "[#{name}] Creating Rails app"
|
22
|
-
rails_new_options = %w[-T -J -S --skip-spring --skip-listen --skip-bootsnap]
|
22
|
+
rails_new_options = %w[-A -G -C -T -J -S --skip-spring --skip-listen --skip-bootsnap --skip-action-mailbox --skip-jbuilder --skip-active-storage]
|
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
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class SamlIdpController <
|
1
|
+
class SamlIdpController < StubSamlIdp::IdpController
|
2
2
|
def new
|
3
3
|
if session[:user_id]
|
4
4
|
@saml_response = idp_make_saml_response(session[:user_id])
|
@@ -79,13 +79,8 @@ class SamlIdpController < SamlIdp::IdpController
|
|
79
79
|
end
|
80
80
|
|
81
81
|
# == SLO functionality, see https://github.com/lawrencepit/ruby-saml-idp/pull/10
|
82
|
-
<% if Rails::VERSION::MAJOR < 5 %>
|
83
|
-
skip_before_filter :validate_saml_request, :only => [:logout, :sp_sign_out]
|
84
|
-
before_filter :validate_saml_slo_request, :only => [:logout]
|
85
|
-
<% else %>
|
86
82
|
skip_before_action :validate_saml_request, :only => [:logout, :sp_sign_out]
|
87
83
|
before_action :validate_saml_slo_request, :only => [:logout]
|
88
|
-
<% end %>
|
89
84
|
|
90
85
|
public
|
91
86
|
|
data/spec/support/sp_template.rb
CHANGED
@@ -6,28 +6,20 @@ attribute_map_resolver = ENV.fetch("ATTRIBUTE_MAP_RESOLVER", "nil")
|
|
6
6
|
saml_session_index_key = ENV.fetch('SAML_SESSION_INDEX_KEY', ":session_index")
|
7
7
|
use_subject_to_authenticate = ENV.fetch('USE_SUBJECT_TO_AUTHENTICATE')
|
8
8
|
idp_settings_adapter = ENV.fetch('IDP_SETTINGS_ADAPTER', "nil")
|
9
|
-
idp_entity_id_reader = ENV.fetch('IDP_ENTITY_ID_READER', "DeviseSamlAuthenticatable::DefaultIdpEntityIdReader")
|
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
|
-
|
12
|
-
if Rails::VERSION::MAJOR < 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR < 2)
|
13
|
-
gsub_file 'config/secrets.yml', /secret_key_base:.*$/, 'secret_key_base: "8b5889df1fcf03f76c7d66da02d8776bcc85b06bed7d9c592f076d9c8a5455ee6d4beae45986c3c030b40208db5e612f2a6ef8283036a352e3fae83c5eda36be"'
|
14
|
-
end
|
11
|
+
ruby_saml_version = ENV.fetch("RUBY_SAML_VERSION")
|
15
12
|
|
16
13
|
gem 'devise_saml_authenticatable', path: File.expand_path("../../..", __FILE__)
|
17
|
-
gem 'ruby-saml',
|
14
|
+
gem 'ruby-saml', ruby_saml_version
|
18
15
|
gem 'thin'
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
gem 'devise', '~> 3.5'
|
25
|
-
gem 'nokogiri', '~> 1.6.8'
|
26
|
-
elsif Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("2.4")
|
27
|
-
gem 'responders', '~> 2.4'
|
17
|
+
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new("3.1")
|
18
|
+
gem 'net-smtp', require: false
|
19
|
+
gem 'net-imap', require: false
|
20
|
+
gem 'net-pop', require: false
|
28
21
|
end
|
29
|
-
|
30
|
-
}
|
22
|
+
|
31
23
|
if Rails::VERSION::MAJOR < 6
|
32
24
|
# sqlite3 is hard-coded in Rails < 6 to v1.3.x
|
33
25
|
gsub_file 'Gemfile', /^gem 'sqlite3'.*$/, "gem 'sqlite3', '~> 1.3.6'"
|
@@ -92,13 +84,24 @@ after_bundle do
|
|
92
84
|
config.saml_configure do |settings|
|
93
85
|
settings.assertion_consumer_service_url = "http://localhost:8020/users/saml/auth"
|
94
86
|
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
87
|
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
88
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
99
89
|
end
|
100
90
|
end
|
101
91
|
CONFIG
|
92
|
+
if Gem::Version.new(ruby_saml_version) >= Gem::Version.new("1.12.0")
|
93
|
+
gsub_file 'config/initializers/devise.rb', /^ config\.saml_configure do \|settings\|$/, <<CONFIG
|
94
|
+
config.saml_configure do |settings|
|
95
|
+
settings.idp_slo_service_url = "http://localhost:8009/saml/logout"
|
96
|
+
settings.idp_sso_service_url = "http://localhost:8009/saml/auth"
|
97
|
+
CONFIG
|
98
|
+
else
|
99
|
+
gsub_file 'config/initializers/devise.rb', /^ config\.saml_configure do \|settings\|$/, <<CONFIG
|
100
|
+
config.saml_configure do |settings|
|
101
|
+
settings.idp_slo_target_url = "http://localhost:8009/saml/logout"
|
102
|
+
settings.idp_sso_target_url = "http://localhost:8009/saml/auth"
|
103
|
+
CONFIG
|
104
|
+
end
|
102
105
|
|
103
106
|
generate :controller, 'home', 'index'
|
104
107
|
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.8.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: 2022-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devise
|
@@ -45,9 +45,10 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- ".github/workflows/ci.yml"
|
48
49
|
- ".gitignore"
|
49
50
|
- ".rspec"
|
50
|
-
- ".
|
51
|
+
- ".ruby-version"
|
51
52
|
- Gemfile
|
52
53
|
- LICENSE
|
53
54
|
- README.md
|
@@ -78,16 +79,16 @@ files:
|
|
78
79
|
- spec/rails_helper.rb
|
79
80
|
- spec/routes/routes_spec.rb
|
80
81
|
- spec/spec_helper.rb
|
81
|
-
- spec/support/Gemfile.rails4
|
82
|
-
- spec/support/Gemfile.rails5
|
83
|
-
- spec/support/Gemfile.rails5.1
|
84
82
|
- spec/support/Gemfile.rails5.2
|
83
|
+
- spec/support/Gemfile.rails6
|
84
|
+
- spec/support/Gemfile.rails6.1
|
85
85
|
- spec/support/attribute-map.yml
|
86
86
|
- spec/support/attribute_map_resolver.rb.erb
|
87
87
|
- spec/support/idp_settings_adapter.rb.erb
|
88
88
|
- spec/support/idp_template.rb
|
89
89
|
- spec/support/rails_app.rb
|
90
90
|
- spec/support/response_encrypted_nameid.xml.base64
|
91
|
+
- spec/support/ruby_saml_support.rb
|
91
92
|
- spec/support/saml_idp-saml_slo_post.html.erb
|
92
93
|
- spec/support/saml_idp_controller.rb.erb
|
93
94
|
- spec/support/sp_template.rb
|
@@ -110,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
111
|
- !ruby/object:Gem::Version
|
111
112
|
version: '0'
|
112
113
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
114
|
+
rubygems_version: 3.3.3
|
114
115
|
signing_key:
|
115
116
|
specification_version: 4
|
116
117
|
summary: SAML Authentication for devise
|
@@ -126,16 +127,16 @@ test_files:
|
|
126
127
|
- spec/rails_helper.rb
|
127
128
|
- spec/routes/routes_spec.rb
|
128
129
|
- spec/spec_helper.rb
|
129
|
-
- spec/support/Gemfile.rails4
|
130
|
-
- spec/support/Gemfile.rails5
|
131
|
-
- spec/support/Gemfile.rails5.1
|
132
130
|
- spec/support/Gemfile.rails5.2
|
131
|
+
- spec/support/Gemfile.rails6
|
132
|
+
- spec/support/Gemfile.rails6.1
|
133
133
|
- spec/support/attribute-map.yml
|
134
134
|
- spec/support/attribute_map_resolver.rb.erb
|
135
135
|
- spec/support/idp_settings_adapter.rb.erb
|
136
136
|
- spec/support/idp_template.rb
|
137
137
|
- spec/support/rails_app.rb
|
138
138
|
- spec/support/response_encrypted_nameid.xml.base64
|
139
|
+
- spec/support/ruby_saml_support.rb
|
139
140
|
- spec/support/saml_idp-saml_slo_post.html.erb
|
140
141
|
- spec/support/saml_idp_controller.rb.erb
|
141
142
|
- spec/support/sp_template.rb
|