oath 1.1.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 +7 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +165 -0
- data/LICENSE.txt +22 -0
- data/NEWS.rdoc +118 -0
- data/README.md +384 -0
- data/Rakefile +6 -0
- data/lib/oath.rb +132 -0
- data/lib/oath/back_door.rb +53 -0
- data/lib/oath/configuration.rb +149 -0
- data/lib/oath/constraints/signed_in.rb +14 -0
- data/lib/oath/constraints/signed_out.rb +14 -0
- data/lib/oath/controller_helpers.rb +161 -0
- data/lib/oath/failure_app.rb +48 -0
- data/lib/oath/field_map.rb +56 -0
- data/lib/oath/param_transformer.rb +38 -0
- data/lib/oath/railtie.rb +11 -0
- data/lib/oath/services.rb +5 -0
- data/lib/oath/services/authentication.rb +40 -0
- data/lib/oath/services/password_reset.rb +27 -0
- data/lib/oath/services/sign_in.rb +25 -0
- data/lib/oath/services/sign_out.rb +24 -0
- data/lib/oath/services/sign_up.rb +42 -0
- data/lib/oath/strategies/password_strategy.rb +42 -0
- data/lib/oath/test/controller_helpers.rb +43 -0
- data/lib/oath/test/helpers.rb +24 -0
- data/lib/oath/version.rb +4 -0
- data/lib/oath/warden_setup.rb +47 -0
- data/oath.gemspec +30 -0
- data/spec/features/user/user_signs_in_spec.rb +14 -0
- data/spec/features/user/user_signs_in_through_back_door_spec.rb +11 -0
- data/spec/features/user/user_tries_to_access_constrained_routes_spec.rb +18 -0
- data/spec/features/user/user_tries_to_access_http_auth_page_spec.rb +9 -0
- data/spec/features/visitor/visitor_fails_to_sign_up_spec.rb +10 -0
- data/spec/features/visitor/visitor_is_unauthorized_spec.rb +8 -0
- data/spec/features/visitor/visitor_signs_in_via_invalid_form_spec.rb +11 -0
- data/spec/features/visitor/visitor_signs_up_spec.rb +40 -0
- data/spec/features/visitor/visitor_tries_to_access_constrained_routes_spec.rb +14 -0
- data/spec/features/visitor/visitor_uses_remember_token_spec.rb +13 -0
- data/spec/oath/configuration_spec.rb +11 -0
- data/spec/oath/controller_helpers_spec.rb +180 -0
- data/spec/oath/field_map_spec.rb +19 -0
- data/spec/oath/services/authentication_spec.rb +25 -0
- data/spec/oath/services/password_reset_spec.rb +24 -0
- data/spec/oath/services/sign_in_spec.rb +13 -0
- data/spec/oath/services/sign_out_spec.rb +13 -0
- data/spec/oath/services/sign_up_spec.rb +49 -0
- data/spec/oath/strategies/password_strategy_spec.rb +23 -0
- data/spec/oath/test_controller_helpers_spec.rb +63 -0
- data/spec/oath/test_helpers_spec.rb +97 -0
- data/spec/oath_spec.rb +27 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/assets/images/rails.png +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +13 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +13 -0
- data/spec/rails_app/app/controllers/application_controller.rb +4 -0
- data/spec/rails_app/app/controllers/basic_auth_controller.rb +7 -0
- data/spec/rails_app/app/controllers/constrained_to_users_controller.rb +5 -0
- data/spec/rails_app/app/controllers/constrained_to_visitors_controller.rb +5 -0
- data/spec/rails_app/app/controllers/failures_controller.rb +5 -0
- data/spec/rails_app/app/controllers/invalid_sessions_controller.rb +2 -0
- data/spec/rails_app/app/controllers/posts_controller.rb +6 -0
- data/spec/rails_app/app/controllers/sessions_controller.rb +26 -0
- data/spec/rails_app/app/controllers/users_controller.rb +23 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/models/user.rb +10 -0
- data/spec/rails_app/app/views/invalid_sessions/new.html.erb +4 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +18 -0
- data/spec/rails_app/app/views/posts/index.html.erb +1 -0
- data/spec/rails_app/app/views/sessions/new.html.erb +5 -0
- data/spec/rails_app/app/views/users/new.html.erb +5 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +58 -0
- data/spec/rails_app/config/boot.rb +6 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +29 -0
- data/spec/rails_app/config/environments/production.rb +54 -0
- data/spec/rails_app/config/environments/test.rb +29 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +15 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/routes.rb +24 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +25 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/spec_helper.rb +37 -0
- metadata +325 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'oath/services/authentication'
|
3
|
+
|
4
|
+
describe Oath::Services::Authentication, '#authentication' do
|
5
|
+
it 'is authenticated for a valid password' do
|
6
|
+
password_digest = BCrypt::Password.create('password')
|
7
|
+
user = double(password_digest: password_digest)
|
8
|
+
auth = Oath::Services::Authentication.new(user, 'password')
|
9
|
+
|
10
|
+
expect(auth.perform).to eq(user)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is not authenticated for the wrong password' do
|
14
|
+
password_digest = BCrypt::Password.create('password')
|
15
|
+
user = double(password_digest: password_digest)
|
16
|
+
auth = Oath::Services::Authentication.new(user, 'drowssap')
|
17
|
+
|
18
|
+
expect(auth.perform).to eq(false)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'is not authenticated without a user' do
|
22
|
+
auth = Oath::Services::Authentication.new(nil, 'password')
|
23
|
+
expect(auth.perform).to eq(false)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'oath/services/password_reset'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
describe Oath::Services::PasswordReset do
|
6
|
+
before do
|
7
|
+
Oath.config.hashing_method = ->(password) { password + "secret" }
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'updates the password with the hashing strategy' do
|
11
|
+
password_digest = Oath.hash_token('password')
|
12
|
+
user = double()
|
13
|
+
field = Oath.config.user_token_store_field
|
14
|
+
allow(user).to receive(:[]=)
|
15
|
+
password_reset = Oath::Services::PasswordReset.new(user, 'password')
|
16
|
+
|
17
|
+
password_reset.perform
|
18
|
+
expect(user).to have_received(:[]=).with(field, 'passwordsecret')
|
19
|
+
end
|
20
|
+
|
21
|
+
after do
|
22
|
+
Oath.config.hashing_method = Oath.config.default_hashing_method
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'oath/services/sign_in'
|
3
|
+
|
4
|
+
describe Oath::Services::SignIn, '#perform' do
|
5
|
+
it 'signs the user in' do
|
6
|
+
user = double()
|
7
|
+
warden = double()
|
8
|
+
allow(warden).to receive(:set_user)
|
9
|
+
|
10
|
+
Oath::Services::SignIn.new(user, warden).perform
|
11
|
+
expect(warden).to have_received(:set_user).with(user)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'oath/services/sign_out'
|
3
|
+
|
4
|
+
describe Oath::Services::SignOut, '#perform' do
|
5
|
+
it 'signs out the user' do
|
6
|
+
warden = double()
|
7
|
+
allow(warden).to receive(:logout)
|
8
|
+
allow(warden).to receive(:user).and_return(double())
|
9
|
+
|
10
|
+
Oath::Services::SignOut.new(warden).perform
|
11
|
+
expect(warden).to have_received(:logout)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'oath/services/sign_up'
|
3
|
+
|
4
|
+
describe Oath::Services::SignUp, '#perform' do
|
5
|
+
it 'creates a user with the right parameters' do
|
6
|
+
allow(User).to receive(:create)
|
7
|
+
user_params = { email: 'email@example.com', password: 'password' }
|
8
|
+
|
9
|
+
Oath::Services::SignUp.new(user_params).perform
|
10
|
+
expect(User).to have_received(:create) do |args|
|
11
|
+
expect(args[:email]).to eq(user_params[:email])
|
12
|
+
expect(Oath.compare_token(args[:password_digest], 'password')).to be_truthy
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'creates a user from the configured user creation method' do
|
17
|
+
user_create_double = double(Proc, call: true)
|
18
|
+
|
19
|
+
user_params = { email: 'email@example.com', password: 'password' }
|
20
|
+
|
21
|
+
with_oath_config(creation_method: user_create_double) do
|
22
|
+
Oath::Services::SignUp.new(user_params).perform
|
23
|
+
end
|
24
|
+
|
25
|
+
expect(user_create_double).to have_received(:call) do |args|
|
26
|
+
expect(Oath.compare_token(args[:password_digest], 'password')).to be_truthy
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'does not create a user with an empty password' do
|
31
|
+
allow(User).to receive(:create)
|
32
|
+
user_params = { email: 'email@example.com', password: '' }
|
33
|
+
|
34
|
+
Oath::Services::SignUp.new(user_params).perform
|
35
|
+
expect(User).to have_received(:create) do |args|
|
36
|
+
expect(args[:password_digest]).to be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'does not create a user with a nil password' do
|
41
|
+
allow(User).to receive(:create)
|
42
|
+
user_params = { email: nil, password: nil }
|
43
|
+
|
44
|
+
Oath::Services::SignUp.new(user_params).perform
|
45
|
+
expect(User).to have_received(:create) do |args|
|
46
|
+
expect(args[:password_digest]).to be_nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Oath
|
4
|
+
module Strategies
|
5
|
+
describe PasswordStrategy do
|
6
|
+
it "bases lookup and token on config values" do
|
7
|
+
params = HashWithIndifferentAccess.new(username: 'test', the_password: 'password')
|
8
|
+
|
9
|
+
with_oath_config(user_lookup_field: "username", user_token_field: "the_password") do
|
10
|
+
env = Rack::MockRequest.env_for("/", params: params)
|
11
|
+
strategy = PasswordStrategy.new(env)
|
12
|
+
expect(strategy).to be_valid
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "it doesn't trigger if params are not provided" do
|
17
|
+
env = Rack::MockRequest.env_for("/")
|
18
|
+
strategy = PasswordStrategy.new(env)
|
19
|
+
expect(strategy).not_to be_valid
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class FakeRequest
|
4
|
+
attr_reader :env
|
5
|
+
def initialize
|
6
|
+
@env = {}
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class FakeController
|
11
|
+
attr_reader :user
|
12
|
+
def sign_in(user)
|
13
|
+
@user = user
|
14
|
+
end
|
15
|
+
|
16
|
+
def sign_out
|
17
|
+
@user = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class FakeSpec
|
22
|
+
cattr_reader :setup_methods
|
23
|
+
attr_reader :request, :controller
|
24
|
+
def initialize(controller = FakeController.new)
|
25
|
+
@request = FakeRequest.new
|
26
|
+
@controller = controller
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.setup(*methods)
|
30
|
+
@@setup_methods = methods
|
31
|
+
end
|
32
|
+
include Oath::Test::ControllerHelpers
|
33
|
+
end
|
34
|
+
|
35
|
+
module Oath
|
36
|
+
module Test
|
37
|
+
describe ControllerHelpers do
|
38
|
+
it 'sets up warden' do
|
39
|
+
expect(FakeSpec.setup_methods).to eq([:store_controller_for_warden, :warden])
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'creates a warden manager' do
|
43
|
+
fake_spec = FakeSpec.new
|
44
|
+
expect(fake_spec.warden).to be_a(Warden::Proxy)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'calls the sign in method on the controller' do
|
48
|
+
controller = FakeController.new
|
49
|
+
fake_spec = FakeSpec.new(controller)
|
50
|
+
fake_spec.sign_in("user")
|
51
|
+
expect(controller.user).to eq("user")
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'calls the sign out method on the controller' do
|
55
|
+
controller = FakeController.new
|
56
|
+
fake_spec = FakeSpec.new(controller)
|
57
|
+
fake_spec.sign_in("user")
|
58
|
+
fake_spec.sign_out
|
59
|
+
expect(controller.user).to eq(nil)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'warden'
|
3
|
+
require 'oath/test/helpers'
|
4
|
+
|
5
|
+
module Warden::Spec
|
6
|
+
module Helpers
|
7
|
+
FAILURE_APP = lambda{|e|[401, {"Content-Type" => "text/plain"}, ["You Fail!"]] }
|
8
|
+
|
9
|
+
def env_with_params(path = "/", params = {}, env = {})
|
10
|
+
method = params.delete(:method) || "GET"
|
11
|
+
env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env)
|
12
|
+
Rack::MockRequest.env_for("#{path}?#{Rack::Utils.build_query(params)}", env)
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup_rack(app = nil, opts = {}, &block)
|
16
|
+
app ||= block if block_given?
|
17
|
+
|
18
|
+
opts[:failure_app] ||= failure_app
|
19
|
+
opts[:default_strategies] ||= [:password]
|
20
|
+
opts[:default_serializers] ||= [:session]
|
21
|
+
blk = opts[:configurator] || proc{}
|
22
|
+
|
23
|
+
Rack::Builder.new do
|
24
|
+
use opts[:session] || Warden::Spec::Helpers::Session unless opts[:nil_session]
|
25
|
+
use Warden::Manager, opts, &blk
|
26
|
+
run app
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def valid_response
|
31
|
+
Rack::Response.new("OK").finish
|
32
|
+
end
|
33
|
+
|
34
|
+
def failure_app
|
35
|
+
Warden::Spec::Helpers::FAILURE_APP
|
36
|
+
end
|
37
|
+
|
38
|
+
def success_app
|
39
|
+
lambda{|e| [200, {"Content-Type" => "text/plain"}, ["You Win"]]}
|
40
|
+
end
|
41
|
+
|
42
|
+
class Session
|
43
|
+
attr_accessor :app
|
44
|
+
def initialize(app,configs = {})
|
45
|
+
@app = app
|
46
|
+
end
|
47
|
+
|
48
|
+
def call(e)
|
49
|
+
e['rack.session'] ||= {}
|
50
|
+
@app.call(e)
|
51
|
+
end
|
52
|
+
end # session
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Oath
|
57
|
+
module Test
|
58
|
+
describe Helpers do
|
59
|
+
include Oath::Test::Helpers
|
60
|
+
include Warden::Spec::Helpers
|
61
|
+
|
62
|
+
before { $captures = [] }
|
63
|
+
after { Oath.test_reset! }
|
64
|
+
|
65
|
+
it 'performs a sign in' do
|
66
|
+
user = double(id: 1)
|
67
|
+
return_value = sign_in(user)
|
68
|
+
app = lambda do |env|
|
69
|
+
$captures << :run
|
70
|
+
expect(env['warden']).to be_authenticated
|
71
|
+
expect(env['warden'].user).to eq(user)
|
72
|
+
valid_response
|
73
|
+
end
|
74
|
+
setup_rack(app).call(env_with_params)
|
75
|
+
|
76
|
+
expect(return_value).to eq(user)
|
77
|
+
expect($captures).to eq([:run])
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'performs a sign out' do
|
81
|
+
user = double(id: 1)
|
82
|
+
sign_in(user)
|
83
|
+
sign_out
|
84
|
+
|
85
|
+
app = lambda do |env|
|
86
|
+
$captures << :run
|
87
|
+
warden = env['warden']
|
88
|
+
expect(warden.user).to be_nil
|
89
|
+
expect(warden).not_to be_authenticated
|
90
|
+
end
|
91
|
+
|
92
|
+
setup_rack(app).call(env_with_params)
|
93
|
+
expect($captures).to eq([:run])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/spec/oath_spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'warden'
|
3
|
+
|
4
|
+
describe 'Oath' do
|
5
|
+
it "stores the warden config" do
|
6
|
+
expect(Oath.warden_config).to be_a Warden::Config
|
7
|
+
end
|
8
|
+
|
9
|
+
it "provides a .test_mode!" do
|
10
|
+
Oath.test_mode!
|
11
|
+
expect(Oath.hash_token('password')).to eql('password')
|
12
|
+
expect(Oath.compare_token('password', 'password')).to be_truthy
|
13
|
+
end
|
14
|
+
|
15
|
+
it "does not lookup with empty params" do
|
16
|
+
allow(Oath::FieldMap).to receive(:new).and_return(fake_field_map)
|
17
|
+
with_oath_config(find_method: -> (conditions) { raise }) do
|
18
|
+
expect(-> { Oath.lookup({}, {}) }).not_to raise_exception
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def fake_field_map
|
23
|
+
double(Oath::FieldMap).tap do |field_map|
|
24
|
+
allow(field_map).to receive(:to_fields).and_return(["foo=1 OR bar=1"])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
RailsApp::Application.load_tasks
|
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class SessionsController < ApplicationController
|
2
|
+
def new
|
3
|
+
end
|
4
|
+
|
5
|
+
def create
|
6
|
+
user = authenticate_session(session_params)
|
7
|
+
|
8
|
+
if sign_in(user)
|
9
|
+
redirect_to posts_path
|
10
|
+
else
|
11
|
+
redirect_to root_path, notice: "Invalid email or password"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def destroy
|
16
|
+
sign_out
|
17
|
+
redirect_to root_path
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def session_params
|
23
|
+
params.require(:session).permit(:email, :password)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|