monban 0.0.1
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.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +149 -0
- data/LICENSE.txt +22 -0
- data/README.md +65 -0
- data/Rakefile +6 -0
- data/lib/generators/monban/controllers/controllers_generator.rb +30 -0
- data/lib/generators/monban/scaffold/scaffold_generator.rb +42 -0
- data/lib/generators/monban/templates/app/controllers/sessions_controller.rb +30 -0
- data/lib/generators/monban/templates/app/controllers/users_controller.rb +26 -0
- data/lib/generators/monban/templates/app/models/user.rb +7 -0
- data/lib/generators/monban/templates/app/views/sessions/new.html.erb +13 -0
- data/lib/generators/monban/templates/app/views/users/new.html.erb +13 -0
- data/lib/generators/monban/templates/db/migrate/create_users.rb +10 -0
- data/lib/generators/monban/templates/scaffold_readme +4 -0
- data/lib/monban.rb +38 -0
- data/lib/monban/configuration.rb +27 -0
- data/lib/monban/controller_helpers.rb +56 -0
- data/lib/monban/controller_helpers/authentication.rb +26 -0
- data/lib/monban/controller_helpers/sign_in.rb +12 -0
- data/lib/monban/controller_helpers/sign_out.rb +11 -0
- data/lib/monban/controller_helpers/sign_up.rb +23 -0
- data/lib/monban/field_map.rb +38 -0
- data/lib/monban/railtie.rb +9 -0
- data/lib/monban/strategies/password_strategy.rb +15 -0
- data/lib/monban/version.rb +3 -0
- data/lib/monban/warden_setup.rb +11 -0
- data/monban.gemspec +29 -0
- data/spec/features/visitor/visitor_signs_up_spec.rb +12 -0
- data/spec/monban/controller_helpers/authentication_spec.rb +25 -0
- data/spec/monban/controller_helpers/sign_in_spec.rb +12 -0
- data/spec/monban/controller_helpers/sign_out_spec.rb +11 -0
- data/spec/monban/controller_helpers/sign_up_spec.rb +17 -0
- data/spec/monban/controller_helpers_spec.rb +124 -0
- data/spec/monban/field_map_spec.rb +18 -0
- data/spec/monban_spec.rb +7 -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/posts_controller.rb +7 -0
- data/spec/rails_app/app/controllers/sessions_controller.rb +18 -0
- data/spec/rails_app/app/controllers/users_controller.rb +15 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/models/user.rb +4 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -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 +8 -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 +7 -0
- metadata +299 -0
data/lib/monban.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "monban/version"
|
2
|
+
require "monban/configuration"
|
3
|
+
require "monban/controller_helpers"
|
4
|
+
require "monban/railtie"
|
5
|
+
require "monban/warden_setup"
|
6
|
+
require "monban/field_map"
|
7
|
+
require "monban/strategies/password_strategy"
|
8
|
+
require "active_support/core_ext/module/attribute_accessors"
|
9
|
+
|
10
|
+
module Monban
|
11
|
+
mattr_accessor :warden_config
|
12
|
+
mattr_accessor :config
|
13
|
+
|
14
|
+
def self.initialize warden_config
|
15
|
+
self.warden_config = warden_config
|
16
|
+
self.config = Monban::Configuration.new
|
17
|
+
if block_given?
|
18
|
+
yield config
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.compare_token(digest, token)
|
23
|
+
config.token_comparison.call(digest, token)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.encrypt_token(token)
|
27
|
+
config.encryption_method.call(token)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.user_class
|
31
|
+
config.user_class.constantize
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.lookup(params, field_map)
|
35
|
+
fields = FieldMap.new(params, field_map).to_fields
|
36
|
+
user_class.where(fields).first
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Monban
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :user_class, :user_token_field, :user_token_store_field
|
4
|
+
attr_accessor :encryption_method, :token_comparison, :user_lookup_field
|
5
|
+
attr_accessor :sign_in_notice
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@user_class = 'User'
|
9
|
+
@user_token_field = 'password'
|
10
|
+
@user_token_store_field = 'password_digest'
|
11
|
+
@user_lookup_field = 'email'
|
12
|
+
@encryption_method = default_encryption_method
|
13
|
+
@token_comparison = default_password_comparison
|
14
|
+
@sign_in_notice = 'You must be signed in'
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_encryption_method
|
18
|
+
->(token) { BCrypt::Password.create(token) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_password_comparison
|
22
|
+
->(digest, unencrypted_token) do
|
23
|
+
BCrypt::Password.new(digest) == unencrypted_token
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
require 'monban/controller_helpers/sign_in'
|
3
|
+
require 'monban/controller_helpers/sign_out'
|
4
|
+
require 'monban/controller_helpers/sign_up'
|
5
|
+
require 'monban/controller_helpers/authentication'
|
6
|
+
require 'active_support/concern'
|
7
|
+
|
8
|
+
module Monban
|
9
|
+
module ControllerHelpers
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
included do
|
12
|
+
helper_method :current_user, :signed_in?
|
13
|
+
end
|
14
|
+
|
15
|
+
def sign_in user
|
16
|
+
SignIn.new(user, warden).perform
|
17
|
+
end
|
18
|
+
|
19
|
+
def sign_out
|
20
|
+
SignOut.new(warden).perform
|
21
|
+
end
|
22
|
+
|
23
|
+
def sign_up user_params
|
24
|
+
SignUp.new(user_params).perform
|
25
|
+
end
|
26
|
+
|
27
|
+
def authenticate_session session_params, field_map = nil
|
28
|
+
user = Monban.lookup(session_params, field_map)
|
29
|
+
password = session_params.delete(Monban.config.user_token_field)
|
30
|
+
authenticate(user, password)
|
31
|
+
end
|
32
|
+
|
33
|
+
def authenticate user, password
|
34
|
+
Authentication.new(user, password).perform
|
35
|
+
end
|
36
|
+
|
37
|
+
def warden
|
38
|
+
env['warden']
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_user
|
42
|
+
warden.user
|
43
|
+
end
|
44
|
+
|
45
|
+
def signed_in?
|
46
|
+
current_user
|
47
|
+
end
|
48
|
+
|
49
|
+
def require_login
|
50
|
+
unless signed_in?
|
51
|
+
flash.notice = Monban.config.sign_in_notice
|
52
|
+
redirect_to '/sign_in'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Monban
|
2
|
+
class Authentication
|
3
|
+
def initialize user, unencrypted_token
|
4
|
+
@user = user
|
5
|
+
@unencrypted_token = unencrypted_token
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform
|
9
|
+
if authenticated?
|
10
|
+
@user
|
11
|
+
else
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def authenticated?
|
19
|
+
@user && Monban.compare_token(@user.send(token_store_field), @unencrypted_token)
|
20
|
+
end
|
21
|
+
|
22
|
+
def token_store_field
|
23
|
+
Monban.config.user_token_store_field
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Monban
|
2
|
+
class SignUp
|
3
|
+
def initialize user_params
|
4
|
+
unencrypted_token = user_params.delete(token_field)
|
5
|
+
token_digest = Monban.encrypt_token(unencrypted_token)
|
6
|
+
@user_params = user_params.merge(token_store_field.to_sym => token_digest)
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
Monban.user_class.create(@user_params.to_hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def token_store_field
|
16
|
+
Monban.config.user_token_store_field
|
17
|
+
end
|
18
|
+
|
19
|
+
def token_field
|
20
|
+
Monban.config.user_token_field
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Monban
|
2
|
+
class FieldMap
|
3
|
+
def initialize params, field_map
|
4
|
+
@params = params
|
5
|
+
@field_map = field_map
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_fields
|
9
|
+
if @field_map
|
10
|
+
params_from_field_map
|
11
|
+
else
|
12
|
+
@params
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def params_from_field_map
|
19
|
+
[query_string, *([value] * lookup_keys.length)]
|
20
|
+
end
|
21
|
+
|
22
|
+
def query_string
|
23
|
+
lookup_keys.map { |key| "#{key} = ?" }.join(" OR ")
|
24
|
+
end
|
25
|
+
|
26
|
+
def session_key
|
27
|
+
@field_map.keys.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def lookup_keys
|
31
|
+
@field_map.values.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def value
|
35
|
+
@params[session_key]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Monban
|
2
|
+
module Strategies
|
3
|
+
class PasswordStrategy < ::Warden::Strategies::Base
|
4
|
+
def valid?
|
5
|
+
params[:email] || params[:password]
|
6
|
+
end
|
7
|
+
|
8
|
+
def authenticate!
|
9
|
+
user = User.find_by_email(params[:email])
|
10
|
+
auth = Authentication.new(user, params[:password])
|
11
|
+
auth.authenticated? ? success!(user) : fail!("Could not log in")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "monban/strategies/password_strategy"
|
2
|
+
|
3
|
+
Warden::Manager.serialize_into_session do |user|
|
4
|
+
user.id
|
5
|
+
end
|
6
|
+
|
7
|
+
Warden::Manager.serialize_from_session do |id|
|
8
|
+
User.find(id)
|
9
|
+
end
|
10
|
+
|
11
|
+
Warden::Strategies.add(:password_strategy, Monban::Strategies::PasswordStrategy)
|
data/monban.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'monban/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "monban"
|
8
|
+
gem.version = Monban::VERSION
|
9
|
+
gem.authors = ["halogenandtoast", "calebthompson"]
|
10
|
+
gem.email = ["halogenandtoast@gmail.com"]
|
11
|
+
gem.description = %q{simple rails authentication}
|
12
|
+
gem.summary = %q{Making rails authentication as simple as possible}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'rails'
|
21
|
+
gem.add_dependency 'bcrypt-ruby'
|
22
|
+
gem.add_dependency 'warden'
|
23
|
+
gem.add_development_dependency 'rspec'
|
24
|
+
gem.add_development_dependency 'rspec-rails'
|
25
|
+
gem.add_development_dependency 'capybara'
|
26
|
+
gem.add_development_dependency 'pry'
|
27
|
+
gem.add_development_dependency 'sqlite3'
|
28
|
+
gem.add_development_dependency 'active_hash'
|
29
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Visitor signs up' do
|
4
|
+
scenario 'with an email and password' do
|
5
|
+
visit sign_up_path
|
6
|
+
fill_in 'user_email', with: 'email@example.com'
|
7
|
+
fill_in 'user_password', with: 'password'
|
8
|
+
click_on 'go'
|
9
|
+
|
10
|
+
page.current_path.should eq(posts_path)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'monban/controller_helpers/authentication'
|
3
|
+
|
4
|
+
describe Monban::Authentication, '#authentication' do
|
5
|
+
it 'is authenticated for a valid password' do
|
6
|
+
password_digest = BCrypt::Password.create('password')
|
7
|
+
user = stub(password_digest: password_digest)
|
8
|
+
auth = Monban::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 = stub(password_digest: password_digest)
|
16
|
+
auth = Monban::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 = Monban::Authentication.new(nil, 'password')
|
23
|
+
expect(auth.perform).to eq(false)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'monban/controller_helpers/sign_in'
|
3
|
+
|
4
|
+
describe Monban::SignIn, '#perform' do
|
5
|
+
it 'signs the user in' do
|
6
|
+
user = double()
|
7
|
+
warden = double()
|
8
|
+
warden.should_receive(:set_user).with(user)
|
9
|
+
|
10
|
+
Monban::SignIn.new(user, warden).perform
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'monban/controller_helpers/sign_up'
|
3
|
+
|
4
|
+
describe Monban::SignUp, '#perform' do
|
5
|
+
it 'creates a user with the right parameters' do
|
6
|
+
create = double
|
7
|
+
stub_const('User', create)
|
8
|
+
user_params = { email: 'email@example.com', password: 'password' }
|
9
|
+
|
10
|
+
create.should_receive(:create) do |args|
|
11
|
+
args[:email].should eq(user_params[:email])
|
12
|
+
args.should have_key(:password_digest)
|
13
|
+
end
|
14
|
+
|
15
|
+
Monban::SignUp.new(user_params).perform
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Monban
|
4
|
+
describe ControllerHelpers do
|
5
|
+
class WardenMock
|
6
|
+
def user; end
|
7
|
+
end
|
8
|
+
class Flash < Struct.new(:notice)
|
9
|
+
end
|
10
|
+
|
11
|
+
class Dummy
|
12
|
+
attr_reader :redirected, :flash
|
13
|
+
def initialize warden
|
14
|
+
@warden = warden
|
15
|
+
@flash = Flash.new
|
16
|
+
@redirected = false
|
17
|
+
end
|
18
|
+
def redirect_to path
|
19
|
+
@redirected = true
|
20
|
+
end
|
21
|
+
def env
|
22
|
+
{ "warden" => @warden }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
before(:each) do
|
27
|
+
@warden = WardenMock.new
|
28
|
+
@dummy = Dummy.new(@warden)
|
29
|
+
@dummy.extend(ControllerHelpers)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'performs a sign in' do
|
33
|
+
user = double()
|
34
|
+
sign_in = double()
|
35
|
+
sign_in.should_receive(:perform)
|
36
|
+
SignIn.should_receive(:new).with(user, @warden).and_return(sign_in)
|
37
|
+
@dummy.sign_in user
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'performs a sign out' do
|
41
|
+
sign_out = double()
|
42
|
+
sign_out.should_receive(:perform)
|
43
|
+
SignOut.should_receive(:new).with(@warden).and_return(sign_out)
|
44
|
+
@dummy.sign_out
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'performs a sign_up' do
|
48
|
+
user_params = double()
|
49
|
+
sign_up = double()
|
50
|
+
sign_up.should_receive(:perform)
|
51
|
+
SignUp.should_receive(:new).with(user_params).and_return(sign_up)
|
52
|
+
@dummy.sign_up user_params
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'authenticates a session' do
|
56
|
+
session_params = double()
|
57
|
+
session_params.should_receive(:delete).with('password').and_return('password')
|
58
|
+
user = double()
|
59
|
+
authentication = double()
|
60
|
+
authentication.should_receive(:perform).and_return(user)
|
61
|
+
Monban.should_receive(:lookup).with(session_params, nil).and_return(user)
|
62
|
+
Authentication.should_receive(:new).with(user, 'password').and_return(authentication)
|
63
|
+
@dummy.authenticate_session(session_params).should == user
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'authenticates a session against multiple fields' do
|
67
|
+
session_params = { 'email_or_username' => 'foo', 'password' => 'password' }
|
68
|
+
field_map = { email_or_username: [:email, :username] }
|
69
|
+
user = double()
|
70
|
+
authentication = double()
|
71
|
+
authentication.should_receive(:perform).and_return(user)
|
72
|
+
Monban.should_receive(:lookup).with(session_params, field_map).and_return(user)
|
73
|
+
Authentication.should_receive(:new).with(user, 'password').and_return(authentication)
|
74
|
+
@dummy.authenticate_session(session_params, field_map).should == user
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns false when it could not authenticate the user' do
|
78
|
+
session_params = double()
|
79
|
+
session_params.should_receive(:delete).with('password').and_return('password')
|
80
|
+
user = double()
|
81
|
+
authentication = double()
|
82
|
+
authentication.should_receive(:perform).and_return(false)
|
83
|
+
Monban.should_receive(:lookup).with(session_params, nil).and_return(user)
|
84
|
+
Authentication.should_receive(:new).with(user, 'password').and_return(authentication)
|
85
|
+
@dummy.authenticate_session(session_params).should == false
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'performs an authenticate' do
|
89
|
+
user = double()
|
90
|
+
password = double()
|
91
|
+
authentication = double()
|
92
|
+
authentication.should_receive(:perform)
|
93
|
+
Authentication.should_receive(:new).with(user, password).and_return(authentication)
|
94
|
+
@dummy.authenticate user, password
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'returns the current user' do
|
98
|
+
@warden.should_receive(:user)
|
99
|
+
@dummy.current_user
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns signed_in?' do
|
103
|
+
@warden.should_receive(:user)
|
104
|
+
@dummy.signed_in?
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'redirects when not signed_in' do
|
108
|
+
@warden.should_receive(:user).and_return(false)
|
109
|
+
@dummy.require_login
|
110
|
+
expect(@dummy.redirected).to eq(true)
|
111
|
+
expect(@dummy.flash.notice).to eq(Monban.config.sign_in_notice)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'does not redirect when signed_in' do
|
115
|
+
@warden.should_receive(:user).and_return(true)
|
116
|
+
@dummy.require_login
|
117
|
+
expect(@dummy.redirected).to eq(false)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns warden' do
|
121
|
+
@dummy.warden.should == @warden
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|