monban 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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