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.
Files changed (68) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +149 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +65 -0
  6. data/Rakefile +6 -0
  7. data/lib/generators/monban/controllers/controllers_generator.rb +30 -0
  8. data/lib/generators/monban/scaffold/scaffold_generator.rb +42 -0
  9. data/lib/generators/monban/templates/app/controllers/sessions_controller.rb +30 -0
  10. data/lib/generators/monban/templates/app/controllers/users_controller.rb +26 -0
  11. data/lib/generators/monban/templates/app/models/user.rb +7 -0
  12. data/lib/generators/monban/templates/app/views/sessions/new.html.erb +13 -0
  13. data/lib/generators/monban/templates/app/views/users/new.html.erb +13 -0
  14. data/lib/generators/monban/templates/db/migrate/create_users.rb +10 -0
  15. data/lib/generators/monban/templates/scaffold_readme +4 -0
  16. data/lib/monban.rb +38 -0
  17. data/lib/monban/configuration.rb +27 -0
  18. data/lib/monban/controller_helpers.rb +56 -0
  19. data/lib/monban/controller_helpers/authentication.rb +26 -0
  20. data/lib/monban/controller_helpers/sign_in.rb +12 -0
  21. data/lib/monban/controller_helpers/sign_out.rb +11 -0
  22. data/lib/monban/controller_helpers/sign_up.rb +23 -0
  23. data/lib/monban/field_map.rb +38 -0
  24. data/lib/monban/railtie.rb +9 -0
  25. data/lib/monban/strategies/password_strategy.rb +15 -0
  26. data/lib/monban/version.rb +3 -0
  27. data/lib/monban/warden_setup.rb +11 -0
  28. data/monban.gemspec +29 -0
  29. data/spec/features/visitor/visitor_signs_up_spec.rb +12 -0
  30. data/spec/monban/controller_helpers/authentication_spec.rb +25 -0
  31. data/spec/monban/controller_helpers/sign_in_spec.rb +12 -0
  32. data/spec/monban/controller_helpers/sign_out_spec.rb +11 -0
  33. data/spec/monban/controller_helpers/sign_up_spec.rb +17 -0
  34. data/spec/monban/controller_helpers_spec.rb +124 -0
  35. data/spec/monban/field_map_spec.rb +18 -0
  36. data/spec/monban_spec.rb +7 -0
  37. data/spec/rails_app/Rakefile +7 -0
  38. data/spec/rails_app/app/assets/images/rails.png +0 -0
  39. data/spec/rails_app/app/assets/javascripts/application.js +13 -0
  40. data/spec/rails_app/app/assets/stylesheets/application.css +13 -0
  41. data/spec/rails_app/app/controllers/application_controller.rb +4 -0
  42. data/spec/rails_app/app/controllers/posts_controller.rb +7 -0
  43. data/spec/rails_app/app/controllers/sessions_controller.rb +18 -0
  44. data/spec/rails_app/app/controllers/users_controller.rb +15 -0
  45. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  46. data/spec/rails_app/app/models/user.rb +4 -0
  47. data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
  48. data/spec/rails_app/app/views/users/new.html.erb +5 -0
  49. data/spec/rails_app/config.ru +4 -0
  50. data/spec/rails_app/config/application.rb +58 -0
  51. data/spec/rails_app/config/boot.rb +6 -0
  52. data/spec/rails_app/config/database.yml +25 -0
  53. data/spec/rails_app/config/environment.rb +5 -0
  54. data/spec/rails_app/config/environments/development.rb +29 -0
  55. data/spec/rails_app/config/environments/production.rb +54 -0
  56. data/spec/rails_app/config/environments/test.rb +29 -0
  57. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/rails_app/config/initializers/inflections.rb +15 -0
  59. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  60. data/spec/rails_app/config/routes.rb +8 -0
  61. data/spec/rails_app/db/seeds.rb +7 -0
  62. data/spec/rails_app/public/404.html +26 -0
  63. data/spec/rails_app/public/422.html +26 -0
  64. data/spec/rails_app/public/500.html +25 -0
  65. data/spec/rails_app/public/favicon.ico +0 -0
  66. data/spec/rails_app/script/rails +6 -0
  67. data/spec/spec_helper.rb +7 -0
  68. 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,12 @@
1
+ module Monban
2
+ class SignIn
3
+ def initialize user, warden
4
+ @user = user
5
+ @warden = warden
6
+ end
7
+
8
+ def perform
9
+ @warden.set_user(@user)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Monban
2
+ class SignOut
3
+ def initialize warden
4
+ @warden = warden
5
+ end
6
+
7
+ def perform
8
+ @warden.logout
9
+ end
10
+ end
11
+ 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,9 @@
1
+ require 'warden'
2
+
3
+ module Monban
4
+ class Railtie < Rails::Railtie
5
+ config.app_middleware.use Warden::Manager do |config|
6
+ Monban.initialize(config)
7
+ end
8
+ end
9
+ 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,3 @@
1
+ module Monban
2
+ VERSION = "0.0.1"
3
+ 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,11 @@
1
+ require 'spec_helper'
2
+ require 'monban/controller_helpers/sign_out'
3
+
4
+ describe Monban::SignOut, '#perform' do
5
+ it 'signs out the user' do
6
+ warden = double()
7
+ warden.should_receive(:logout)
8
+
9
+ Monban::SignOut.new(warden).perform
10
+ end
11
+ 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