proxy_authentication 0.0.4
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +34 -0
- data/lib/proxy_authentication.rb +68 -0
- data/lib/proxy_authentication/authentication_cipher.rb +59 -0
- data/lib/proxy_authentication/cipher.rb +64 -0
- data/lib/proxy_authentication/helpers.rb +31 -0
- data/lib/proxy_authentication/test_helpers.rb +44 -0
- data/lib/proxy_authentication/version.rb +3 -0
- data/lib/tasks/proxy_authentication_tasks.rake +4 -0
- data/test/authentication_cipher_test.rb +83 -0
- data/test/authentication_controller_test.rb +72 -0
- data/test/cipher_test.rb +21 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +10 -0
- data/test/dummy/app/controllers/home_controller.rb +6 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/user.rb +13 -0
- data/test/dummy/app/views/home/show.html.erb +3 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/proxy_authentication.rb +6 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +59 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +360 -0
- data/test/dummy/log/production.log +0 -0
- data/test/dummy/log/test.log +4612 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/0-zEvwlFHnH_Pe19oAQdm9AvqiKmpSxMkm4hkxwuO2Q.cache +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/0ieeKnMtadPClPcf7n4_-7f9dFAa5EKPn-nhh8g4E_I.cache +1 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/3PrmpHHPB63uKo_J8DA17m8A2ifRM2oQwV2ht-J0-is.cache +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/3fB7XY5WyPu8FySUeyC372vbXJ2Ix4iB1QaNHXbk_BY.cache +1 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +2 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/EHcymtlGKlOMMf7gOs-X2_jpvcBTW92Qeaxu2B5-Wbg.cache +1 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/KwafFPkbuDYTVqsISFs_yCHgXK4p07hzR6veAzDwuuc.cache +1 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +3 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/SGxtd6iKmB2TMwH-VOx-jVYXh5m_09UjNEOkifPHLL0.cache +1 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/UGriVNvoxX6203fJqmsTHnKUagkF3JBw6nn6mfw3w5g.cache +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/dOuzt3uIJxwUNVKI0daCeNk0PQDI8MYqLlfcMHzc6-E.cache +1 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/glnuwd6ozsfCCVdZ5uagYczBMDB0D-W-i6JAuDfKvoc.cache +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +3 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/o1kR1PA3NiPrjlfxeTACSvO3YLlOPjUQi2YkxURHJCs.cache +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/zW42jTcqmsgkuFrYkna-BYD_J6kKuRW16OhweSyNss0.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/4udH3Kvt3C2cCGuaQlNudmK4ORwSvcL3wly1cxYQSCI.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/9jPCqzZvmeFf31Rz8y3OEo8OQXEHVcwmLgkx0tXs-o8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/CNAnhGuda7RU2cy1LoLZtgOXanVdsdgrZA6YLhYkfCg.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Ct2bBJ2j5lnvWEsqMkvxgrBschDpIaLnrbFjNlNqkwQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/GQgusgBOwVSgRbnk7ZD_byHBEGf5x8tB7KEmS_Nn7go.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/IsR8qItXiIDT-adWpc8GqBPg7rG0qBqvCOj3K-VsoT8.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/OwNOsob6Xcj4v6Rh7nE6il11_qI3Y1aZgQLbWcwpcAA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Qx1JQQo3e3jJx9EX_SjE51tC9izB-kU-Dx3Lxs9pJog.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/XLdrSXICyvmXq6FCVF8xNBTy0wtRmX087QMWRS5XGXA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/_Slb8psWEK6pgvtcS5M2j38q9zUh6Xl86eQqnw5yjWY.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/h3E0XD4wRGR5pmdK_kHHGggBEU01INtD8LDnoR8Nt_w.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ldn4mjNpwK-bJF0geft9TpHRidEVK2xKXMx4AqhIMWI.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/o2kqwqoUQ3gkgncZO1IWdVRzFD0wCSQ-HyL62cINFOU.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pQIgTfLmEPykNamzxdqBww21SMT7YlZlZGy6hgQ6eVE.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/td9wUl9SLRnSSgE2ZK_VqCzLxTkFiCW50KkOhE916Wo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vvv17q90-DU3Hs_cfDWuupUuw9khOZXTqTOEMhCl3ek.cache +1 -0
- data/test/proxy_authentication_test.rb +7 -0
- data/test/test_helper.rb +26 -0
- metadata +272 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 6b2be32c03d684e55f8f79667693aa29b49bc889
|
|
4
|
+
data.tar.gz: deac0c0703ba178036555364cab6d2c7a22cee1b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e96d2557e4fee2f2817f2ab85944591456fff06b91835e5eb892463694805a11667834b4c79350e0ff0dfee04562f1f4f34d40f17ab76dd7a24ae8baea33fa85
|
|
7
|
+
data.tar.gz: 91867ff95fbd785c90da9d5415b615c4f2c3ee0113f2eb1d32585ce5195190e23428e516f56da42e2b0f887749d971cb25f50d729a94d21591045c099fa5a9a0
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2015 Jesús Dugarte
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'rdoc/task'
|
|
8
|
+
|
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
11
|
+
rdoc.title = 'ProxyAuthentication'
|
|
12
|
+
rdoc.options << '--line-numbers'
|
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Bundler::GemHelper.install_tasks
|
|
23
|
+
|
|
24
|
+
require 'rake/testtask'
|
|
25
|
+
|
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
|
27
|
+
t.libs << 'lib'
|
|
28
|
+
t.libs << 'test'
|
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
|
30
|
+
t.verbose = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
task default: :test
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'warden'
|
|
2
|
+
require 'proxy_authentication/helpers'
|
|
3
|
+
require 'proxy_authentication/authentication_cipher'
|
|
4
|
+
|
|
5
|
+
module ProxyAuthentication
|
|
6
|
+
|
|
7
|
+
mattr_accessor :user_class
|
|
8
|
+
@@user_class = 'User'
|
|
9
|
+
|
|
10
|
+
mattr_accessor :redirect_to_if_authentication_failed
|
|
11
|
+
@@redirect_to_if_authentication_failed = nil
|
|
12
|
+
|
|
13
|
+
mattr_accessor :secret_key
|
|
14
|
+
@@secret_key = nil
|
|
15
|
+
|
|
16
|
+
mattr_accessor :validate_with_block
|
|
17
|
+
@@validate_with_block = nil
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
|
|
21
|
+
def setup
|
|
22
|
+
setup_warden
|
|
23
|
+
include_helpers
|
|
24
|
+
yield self if block_given?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def validate_with &block
|
|
28
|
+
@@validate_with_block = block
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def setup_warden
|
|
34
|
+
insert_warden_middleware
|
|
35
|
+
define_warden_strategy
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def insert_warden_middleware
|
|
39
|
+
Rails.configuration.middleware.insert_before ActionDispatch::ParamsParser, Warden::Manager do |manager|
|
|
40
|
+
manager.default_strategies :proxy_authentication_via_token
|
|
41
|
+
manager.serialize_into_session { |user| ProxyAuthentication::AuthenticationCipher.encode user }
|
|
42
|
+
manager.serialize_from_session { |hash| ProxyAuthentication::AuthenticationCipher.decode hash }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def define_warden_strategy
|
|
47
|
+
Warden::Strategies.add(:proxy_authentication_via_token) do
|
|
48
|
+
|
|
49
|
+
def valid?
|
|
50
|
+
params['u'].present? && env['action_controller.instance'].present?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def authenticate!
|
|
54
|
+
rails_request = env['action_controller.instance'].request
|
|
55
|
+
user = ProxyAuthentication::AuthenticationCipher.decode params['u'].to_s, rails_request
|
|
56
|
+
user.present? ? success!(user) : fail
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def include_helpers
|
|
63
|
+
ActionController::Base.send :include, ::ProxyAuthentication::Helpers
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'proxy_authentication/cipher'
|
|
2
|
+
|
|
3
|
+
module ProxyAuthentication
|
|
4
|
+
|
|
5
|
+
module AuthenticationCipher
|
|
6
|
+
|
|
7
|
+
extend self
|
|
8
|
+
|
|
9
|
+
def encode user, request = nil
|
|
10
|
+
data = request_info(request) << user.to_authentication_hash.to_json
|
|
11
|
+
Cipher.encode_data_as_url_token data
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def decode token, request = nil
|
|
15
|
+
data = Cipher.decode_data_from_url_token token
|
|
16
|
+
return nil if data.nil? || !valid_request?(data, request)
|
|
17
|
+
extract_user data.last
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def request_info request
|
|
23
|
+
[
|
|
24
|
+
ip(request.try(:remote_ip)),
|
|
25
|
+
Time.now.to_i,
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# TODO: add validation for the time of the request
|
|
30
|
+
# e.g. only consider a request valid if it was generated in the last 15 minutes
|
|
31
|
+
def valid_request? data, request
|
|
32
|
+
return true if request.nil?
|
|
33
|
+
return validate_with_block(data, request) if ProxyAuthentication.validate_with_block.present?
|
|
34
|
+
ip(request.remote_ip) == ip(data.first)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ip value
|
|
38
|
+
return 'localhost' if %w[ localhost 127.0.0.1 ::1 ].include?(value)
|
|
39
|
+
value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def extract_user data
|
|
43
|
+
hash = JSON.parse data
|
|
44
|
+
klass = ProxyAuthentication.user_class.to_s.classify.constantize
|
|
45
|
+
klass.from_authentication_hash hash
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def validate_with_block data, request
|
|
49
|
+
arguments = {
|
|
50
|
+
ip: data.first,
|
|
51
|
+
time: Time.at(data.second.to_i),
|
|
52
|
+
user: extract_user(data.last),
|
|
53
|
+
}
|
|
54
|
+
ProxyAuthentication.validate_with_block.call ip(request.remote_ip), arguments
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module ProxyAuthentication
|
|
2
|
+
|
|
3
|
+
module Cipher
|
|
4
|
+
|
|
5
|
+
extend self
|
|
6
|
+
|
|
7
|
+
def encode_data_as_url_token data, separator = "\n"
|
|
8
|
+
data = data.join separator
|
|
9
|
+
string = [ data, signature_for(data) ].join separator
|
|
10
|
+
Base64.urlsafe_encode64 string
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def decode_data_from_url_token token_base64, separator = "\n"
|
|
14
|
+
raw_data = decode64 token_base64
|
|
15
|
+
return nil if raw_data.nil?
|
|
16
|
+
|
|
17
|
+
data = raw_data.split separator
|
|
18
|
+
actual_signature = data.pop
|
|
19
|
+
expected_signature = signature_for data.join(separator)
|
|
20
|
+
return nil if actual_signature != expected_signature
|
|
21
|
+
|
|
22
|
+
data
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def signature_for string
|
|
28
|
+
OpenSSL::HMAC.hexdigest OpenSSL::Digest::SHA1.new, secret_key, string
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def decode64 token_base64
|
|
32
|
+
Base64.urlsafe_decode64 token_base64
|
|
33
|
+
rescue ArgumentError => exception
|
|
34
|
+
return nil if exception.message =~ /invalid base64/
|
|
35
|
+
raise exception
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def secret_key
|
|
39
|
+
ProxyAuthentication.secret_key || Rails.application.secrets.secret_key_base
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Backport Base64.urlsafe_[en|de]code64 methods to ruby 1.8
|
|
47
|
+
# https://gist.github.com/phallstrom/1397972
|
|
48
|
+
if RUBY_VERSION < '1.9'
|
|
49
|
+
begin
|
|
50
|
+
require 'base64'
|
|
51
|
+
rescue LoadError
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if defined? ::Base64
|
|
55
|
+
module ::Base64
|
|
56
|
+
def self.urlsafe_encode64(bin)
|
|
57
|
+
[bin].pack("m0").tr("+/", "-_")
|
|
58
|
+
end
|
|
59
|
+
def self.urlsafe_decode64(str)
|
|
60
|
+
str.tr("-_", "+/").unpack("m0").first
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module ProxyAuthentication
|
|
2
|
+
|
|
3
|
+
module Helpers
|
|
4
|
+
|
|
5
|
+
def self.included mod
|
|
6
|
+
mod.helper_method :current_user, :user_signed_in?
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def current_user
|
|
10
|
+
@current_user ||= warden.user
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def user_signed_in?
|
|
14
|
+
!!current_user
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def authenticate_user_from_token!
|
|
20
|
+
warden.logout if warden.authenticated? && params['u'].present?
|
|
21
|
+
warden.authenticate
|
|
22
|
+
redirect_to ProxyAuthentication.redirect_to_if_authentication_failed if warden.unauthenticated?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def warden
|
|
26
|
+
request.env['warden']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Based on Kentaro Imai's code:
|
|
2
|
+
# http://kentaroimai.com/articles/1-controller-test-helpers-for-warden
|
|
3
|
+
|
|
4
|
+
module ProxyAuthentication
|
|
5
|
+
|
|
6
|
+
module TestHelpers
|
|
7
|
+
|
|
8
|
+
def self.included base
|
|
9
|
+
base.class_eval do
|
|
10
|
+
setup :setup_controller_for_warden, :warden if respond_to? :setup
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sign_in user
|
|
15
|
+
warden.instance_variable_get(:@users).delete :default
|
|
16
|
+
warden.session_serializer.store user, :default
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def sign_out
|
|
20
|
+
@controller.instance_variable_set :@current_user, nil
|
|
21
|
+
user = warden.instance_variable_get(:@users).delete :default
|
|
22
|
+
warden.session_serializer.delete :default, user
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# We need to setup the environment variables and the response in the controller
|
|
28
|
+
def setup_controller_for_warden
|
|
29
|
+
@request.env['action_controller.instance'] = @controller
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Quick access to Warden::Proxy (memoized at setup)
|
|
33
|
+
def warden
|
|
34
|
+
@warden ||= new_warden_proxy
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def new_warden_proxy
|
|
38
|
+
manager = Warden::Manager.new nil, &Rails.application.config.middleware.detect { |m| m.name == 'Warden::Manager'}.block
|
|
39
|
+
@request.env['warden'] = Warden::Proxy.new @request.env, manager
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class AuthenticationCipherTest < ActiveSupport::TestCase
|
|
4
|
+
|
|
5
|
+
test "user remains the same" do
|
|
6
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user
|
|
7
|
+
assert_equal user, ProxyAuthentication::AuthenticationCipher.decode(token)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
test "if no validation block is provided, returns something if the ip addresses are the same" do
|
|
11
|
+
request = ActionDispatch::Request.new 'REMOTE_ADDR' => '1.2.3.4'
|
|
12
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, request
|
|
13
|
+
decoded = ProxyAuthentication::AuthenticationCipher.decode token, request
|
|
14
|
+
assert_not_nil decoded
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "if no validation block is provided, returns nil if the ip addresses are different" do
|
|
18
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, ActionDispatch::Request.new('REMOTE_ADDR' => '1.2.3.4')
|
|
19
|
+
decoded = ProxyAuthentication::AuthenticationCipher.decode token, ActionDispatch::Request.new('REMOTE_ADDR' => '0.0.0.0')
|
|
20
|
+
assert_nil decoded
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "call the validation block, if provided" do
|
|
24
|
+
validation_block = -> {}
|
|
25
|
+
validation_block.expects :call
|
|
26
|
+
ProxyAuthentication.validate_with &validation_block
|
|
27
|
+
|
|
28
|
+
request = ActionDispatch::Request.new 'REMOTE_ADDR' => '1.2.3.4'
|
|
29
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, request
|
|
30
|
+
ProxyAuthentication::AuthenticationCipher.decode token, request
|
|
31
|
+
ProxyAuthentication.validate_with
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
test "call the validation block with the request information" do
|
|
35
|
+
validation_block = lambda {}
|
|
36
|
+
time = Time.now
|
|
37
|
+
ip = '1.2.3.4'
|
|
38
|
+
arguments = {
|
|
39
|
+
ip: ip,
|
|
40
|
+
time: Time.at(time.to_i),
|
|
41
|
+
user: user,
|
|
42
|
+
}
|
|
43
|
+
Time.stubs(:now).returns(time)
|
|
44
|
+
validation_block.expects(:call).with(ip, arguments)
|
|
45
|
+
ProxyAuthentication.validate_with &validation_block
|
|
46
|
+
|
|
47
|
+
request = ActionDispatch::Request.new 'REMOTE_ADDR' => ip
|
|
48
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, request
|
|
49
|
+
ProxyAuthentication::AuthenticationCipher.decode token, request
|
|
50
|
+
ProxyAuthentication.validate_with
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
test "returns nil if the validation block return false" do
|
|
54
|
+
validation_block = lambda { |*| false }
|
|
55
|
+
ProxyAuthentication.validate_with &validation_block
|
|
56
|
+
|
|
57
|
+
request = ActionDispatch::Request.new 'REMOTE_ADDR' => '1.2.3.4'
|
|
58
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, request
|
|
59
|
+
decoded = ProxyAuthentication::AuthenticationCipher.decode token, request
|
|
60
|
+
ProxyAuthentication.validate_with
|
|
61
|
+
|
|
62
|
+
assert_nil decoded
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
test "returns something if the validation block return true" do
|
|
66
|
+
validation_block = lambda { |*| true }
|
|
67
|
+
ProxyAuthentication.validate_with &validation_block
|
|
68
|
+
|
|
69
|
+
request = ActionDispatch::Request.new 'REMOTE_ADDR' => '1.2.3.4'
|
|
70
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, request
|
|
71
|
+
decoded = ProxyAuthentication::AuthenticationCipher.decode token, request
|
|
72
|
+
ProxyAuthentication.validate_with
|
|
73
|
+
|
|
74
|
+
assert_not_nil decoded
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def user
|
|
80
|
+
@user = User.new 1, 'User', 'user@example.com'
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class AuthenticationControllerTest < ActionController::TestCase
|
|
4
|
+
|
|
5
|
+
tests HomeController
|
|
6
|
+
|
|
7
|
+
test "accesing root without authenticating a user redirects to sign in" do
|
|
8
|
+
get :show
|
|
9
|
+
|
|
10
|
+
assert_redirection_to_sign_in
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test "accesing root with a valid authentication hash signs in the user" do
|
|
14
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, request
|
|
15
|
+
|
|
16
|
+
get :show, u: token
|
|
17
|
+
|
|
18
|
+
assert_successful_sign_in
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
test "accesing root with a authentication hash from a different ip address redirects to sign in" do
|
|
22
|
+
token = ProxyAuthentication::AuthenticationCipher.encode user, ActionDispatch::Request.new('REMOTE_ADDR' => '1.2.3.4')
|
|
23
|
+
|
|
24
|
+
get :show, u: token
|
|
25
|
+
|
|
26
|
+
assert_redirection_to_sign_in
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
test "accesing root with an invalid authentication hash redirects to sign in" do
|
|
30
|
+
get :show, u: 'not a valid hash'
|
|
31
|
+
|
|
32
|
+
assert_redirection_to_sign_in
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
test "accesing root after a valid session was created doesn't require sign in" do
|
|
36
|
+
sign_in user
|
|
37
|
+
|
|
38
|
+
get :show
|
|
39
|
+
|
|
40
|
+
assert_successful_sign_in
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test "accesing root with a valid authentication hash after a valid session was created should change the current user" do
|
|
44
|
+
sign_in user
|
|
45
|
+
other_user = User.new 2, 'Other User', 'other_user@example.com'
|
|
46
|
+
token = ProxyAuthentication::AuthenticationCipher.encode other_user, request
|
|
47
|
+
|
|
48
|
+
get :show, u: token
|
|
49
|
+
|
|
50
|
+
assert_equal other_user.id, @controller.current_user.id
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def user
|
|
56
|
+
@user = User.new 1, 'User', 'user@example.com'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def assert_redirection_to_sign_in
|
|
60
|
+
assert_response :redirect
|
|
61
|
+
assert_redirected_to ProxyAuthentication.redirect_to_if_authentication_failed
|
|
62
|
+
refute @controller.user_signed_in?
|
|
63
|
+
assert_nil @controller.current_user
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def assert_successful_sign_in
|
|
67
|
+
assert_response :success
|
|
68
|
+
assert @controller.user_signed_in?
|
|
69
|
+
assert_not_nil @controller.current_user
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|