monban 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ac25191fae11dd25ac1ddda52af84f5eba6f047
4
- data.tar.gz: 840b51a801541c1bb9ded597adc1a7fa6476ff44
3
+ metadata.gz: cd09aa083126137a0de785ca3c26497485606236
4
+ data.tar.gz: c5280f21c291872564c4785f29951baa4292f541
5
5
  SHA512:
6
- metadata.gz: 1aa388fa2a8b0de5977985f8a8d183b6cda66c018c7467385cc05fd20ed896ddcaf6674958ba9619b95879238a7fad2ef9f1795795ef4be530bfb665457eb3ef
7
- data.tar.gz: 108534d568451cb69bf755bdc02285e1bfbc594fc080ebbf17747777e011403499c3c85bc205560f31554d78f13b31d56868389bffbdb0563456859ba84b7060
6
+ metadata.gz: c49cea5a7cef423381cd17dae58d410ce93d3ab919b27cd25d7256a0a19e662464ed80a97ddb9fec4fc33e2e161f07478981368234c3340b94b7458fbffbc693
7
+ data.tar.gz: 3e6ca5fd876a5c8af8ead41c791eb2a57a342003a9ef6404860ef14950edd1598fb2fc7f8d1b43f9615d0a457b39d6301017de2d50661fd9c601724e339ed892
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- monban (0.1.0)
4
+ monban (0.2.0)
5
5
  bcrypt
6
6
  rails
7
7
  warden
@@ -36,7 +36,7 @@ GEM
36
36
  thread_safe (~> 0.1)
37
37
  tzinfo (~> 1.1)
38
38
  arel (5.0.1.20140414130214)
39
- bcrypt (3.1.7)
39
+ bcrypt (3.1.10)
40
40
  builder (3.2.2)
41
41
  capybara (2.0.2)
42
42
  mime-types (>= 1.16)
data/NEWS.rdoc CHANGED
@@ -1,3 +1,14 @@
1
+ == 0.2.0
2
+ * `sign_in` test helper now returns the user
3
+ * `authenticate_session` arguments are coerced to Hash
4
+ * Monban::BackDoor can be configured with a block
5
+ * Document validation suggestions
6
+ * Document locale suggestions
7
+ * Deprecate usage of Monban.user_class in favor of Monban.config.user_class
8
+ * Make warden strategy configurable via Monban.config.authentication_strategy
9
+ * Extract warden setup into the WardenSetup class
10
+ * Document layout suggestions
11
+
1
12
  == 0.1.1
2
13
  * Link to Rubydoc in documentation
3
14
  * Fix header in documentation
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
 
2
2
  # Monban 門番
3
3
 
4
+ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/halogenandtoast/monban?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
+
4
6
  [![Build Status](https://travis-ci.org/halogenandtoast/monban.png?branch=master)](https://travis-ci.org/halogenandtoast/monban)
5
7
  [![Code Climate](https://codeclimate.com/github/halogenandtoast/monban.png)](https://codeclimate.com/github/halogenandtoast/monban)
6
8
 
@@ -53,6 +55,64 @@ configure and change any of these:
53
55
  - You should have an `email` and `password_digest` column on your `User`
54
56
  - Passwords will be handled with BCrypt
55
57
 
58
+ ### Suggestions
59
+
60
+ #### Validations
61
+
62
+ Monban doesn't add validations to your user model unless you're using [monban generators] so it's suggested to add the following validations:
63
+
64
+ ```ruby
65
+ validates :email, presence: true, uniqueness: true
66
+ validates :password_digest, presence: true
67
+ ```
68
+
69
+ In addition to that you'll want to add the following to your `config/locale/en.yml`:
70
+
71
+ ```yaml
72
+ en:
73
+ activerecord:
74
+ attributes:
75
+ user:
76
+ password_digest: "Password"
77
+ ```
78
+
79
+ Which will generate the error message `Password can't be blank` instead of `Password digest can't be blank`.
80
+
81
+ #### Layout changes
82
+
83
+ It is suggested you add something like this to your application layout:
84
+
85
+ ```erb
86
+ <% if signed_in? %>
87
+ <%= link_to "Sign out", session_path, method: :delete %>
88
+ <% else %>
89
+ <%= link_to "Sign in", new_session_path %>
90
+ <%= link_to "Sign up", new_user_path %>
91
+ <% end %>
92
+ ```
93
+
94
+ #### Guest user
95
+
96
+ If you want to introduce a Guest object when a user is not signed in, you can override Monban's `current_user` method in your `ApplicationController`:
97
+
98
+ ```ruby
99
+ def current_user
100
+ super || Guest.new
101
+ end
102
+ ```
103
+
104
+ In `app/models/`, define a `Guest` class:
105
+
106
+ ```ruby
107
+ class Guest
108
+ def name
109
+ "Guest"
110
+ end
111
+ end
112
+ ```
113
+
114
+ This article on the [Null Object Pattern](http://robots.thoughtbot.com/handling-associations-on-null-objects) provides a good explanation of why you might want to do this.
115
+
56
116
  ### Controller Additions
57
117
 
58
118
  Monban provides the following controller methods:
@@ -73,6 +133,25 @@ And this filter:
73
133
 
74
134
  - `require_login`
75
135
 
136
+ ### Routing Constraints
137
+
138
+ To authorize users in `config/routes.rb`:
139
+
140
+ ```ruby
141
+ require "monban/constraints/signed_in"
142
+ require "monban/constraints/signed_out"
143
+
144
+ Blog::Application.routes.draw do
145
+ constraints Monban::Constraints::SignedIn.new do
146
+ root "dashboards#show", as: :dashboard
147
+ end
148
+
149
+ constraints Monban::Constraints::SignedOut.new do
150
+ root "landings#show"
151
+ end
152
+ end
153
+ ```
154
+
76
155
  ## Usage in Tests
77
156
 
78
157
  ### Test mode
@@ -136,6 +215,16 @@ To enable this functionality you'll want to add the following to `config/environ
136
215
  config.middleware.insert_after Warden::Manager, Monban::BackDoor
137
216
  ```
138
217
 
218
+ If you'd like to find your User model by a field other than `id`, insert the
219
+ middleware with a block that accepts the `as` query parameter and returns an
220
+ instance of your User model:
221
+
222
+ ```ruby
223
+ config.middleware.insert_after Warden::Manager, Monban::BackDoor do |user_param|
224
+ User.find_by(username: user_param)
225
+ end
226
+ ```
227
+
139
228
  ### Controller Specs
140
229
 
141
230
  If you are going to write controller tests, helpers are provided for those as well:
@@ -16,8 +16,12 @@ module Monban
16
16
  class BackDoor
17
17
  # Create the a new BackDoor middleware for test purposes
18
18
  # @return [BackDoor]
19
- def initialize(app)
19
+ def initialize(app, &block)
20
20
  @app = app
21
+
22
+ if block
23
+ @sign_in_block = block
24
+ end
21
25
  end
22
26
 
23
27
  # Execute the BackDoor middleware signing in the user specified with :as
@@ -33,9 +37,17 @@ module Monban
33
37
  user_id = params['as']
34
38
 
35
39
  if user_id.present?
36
- user = Monban.user_class.find(user_id)
40
+ user = find_user(user_id)
37
41
  env["warden"].set_user(user)
38
42
  end
39
43
  end
44
+
45
+ def find_user(user_id)
46
+ if @sign_in_block
47
+ @sign_in_block.call(user_id)
48
+ else
49
+ Monban.config.user_class.find(user_id)
50
+ end
51
+ end
40
52
  end
41
53
  end
@@ -10,6 +10,7 @@ module Monban
10
10
  attr_accessor :failure_app
11
11
  attr_accessor :creation_method, :find_method
12
12
  attr_accessor :no_login_handler, :no_login_redirect
13
+ attr_accessor :authentication_strategy
13
14
 
14
15
  attr_writer :user_class
15
16
 
@@ -18,14 +19,14 @@ module Monban
18
19
  setup_token_hashing
19
20
  setup_notices
20
21
  setup_services
21
- setup_requirements
22
+ setup_warden_requirements
22
23
  end
23
24
 
24
25
  # Default creation method. Can be overriden via {Monban.configure}
25
26
  #
26
27
  # @see #creation_method=
27
28
  def default_creation_method
28
- ->(params) { Monban.user_class.create(params) }
29
+ ->(params) { Monban.config.user_class.create(params) }
29
30
  end
30
31
 
31
32
  # Default hashing method. Can be overriden via {Monban.configure}
@@ -44,9 +45,9 @@ module Monban
44
45
  # Default find method. Can be overriden via {Monban.configure}
45
46
  #
46
47
  # @see #find_method=
47
- # @see Monban.user_class
48
+ # @see Monban.config.user_class
48
49
  def default_find_method
49
- ->(params) { Monban.user_class.find_by(params) }
50
+ ->(params) { Monban.config.user_class.find_by(params) }
50
51
  end
51
52
 
52
53
  # Default token comparison method. Can be overriden via {Monban.configure}
@@ -107,8 +108,9 @@ module Monban
107
108
  @password_reset_service = Monban::Services::PasswordReset
108
109
  end
109
110
 
110
- def setup_requirements
111
+ def setup_warden_requirements
111
112
  @failure_app = lambda{|e|[401, {"Content-Type" => "text/plain"}, ["Authorization Failed"]] }
113
+ @authentication_strategy = Monban::Strategies::PasswordStrategy
112
114
  end
113
115
  end
114
116
  end
@@ -98,8 +98,9 @@ module Monban
98
98
 
99
99
  def authenticate_session session_params, field_map = nil
100
100
  token_field = Monban.config.user_token_field
101
- password = session_params.fetch(token_field)
102
- user = Monban.lookup(session_params.except(token_field), field_map)
101
+ session_params_hash = session_params.to_h.symbolize_keys
102
+ password = session_params_hash.fetch(token_field)
103
+ user = Monban.lookup(session_params_hash.except(token_field), field_map)
103
104
  authenticate(user, password)
104
105
  end
105
106
 
@@ -23,7 +23,7 @@ module Monban
23
23
 
24
24
  def token_digest(user_params)
25
25
  undigested_token = user_params[token_field]
26
- unless undigested_token.empty?
26
+ unless undigested_token.blank?
27
27
  Monban.hash_token(undigested_token)
28
28
  end
29
29
  end
@@ -15,7 +15,7 @@ module Monban
15
15
 
16
16
  # Authenticates for warden
17
17
  def authenticate!
18
- user = Monban.user_class.find_by(lookup_field => lookup_field_value)
18
+ user = Monban.config.user_class.find_by(lookup_field => lookup_field_value)
19
19
  auth = Monban.config.authentication_service.new(user, token_field_value)
20
20
  auth.authenticated? ? success!(user) : fail!("Could not log in")
21
21
  end
@@ -8,8 +8,11 @@ module Monban
8
8
 
9
9
  # Sign a user in
10
10
  # @param user [User] user to sign in
11
+ # @returns user [User] signed in user
11
12
  def sign_in user
12
13
  login_as user
14
+
15
+ user
13
16
  end
14
17
 
15
18
  # Sign a user out
@@ -1,4 +1,4 @@
1
1
  module Monban
2
- # 0.1.1
3
- VERSION = "0.1.1"
2
+ # 0.2.0
3
+ VERSION = "0.2.0"
4
4
  end
@@ -1,12 +1,44 @@
1
1
  require 'warden'
2
2
  require "monban/strategies/password_strategy"
3
3
 
4
- Warden::Manager.serialize_into_session do |user|
5
- user.id
6
- end
4
+ module Monban
5
+ # Sets up warden specifics for working with monban
6
+ class WardenSetup
7
+ def initialize(warden_config)
8
+ @warden_config = warden_config
9
+ end
7
10
 
8
- Warden::Manager.serialize_from_session do |id|
9
- Monban.user_class.find_by(id: id)
10
- end
11
+ # Sets up warden specifics for working with monban:
12
+ # * Session serialization
13
+ # * Strategy
14
+ # * Failure app
15
+ def call
16
+ setup_warden_manager
17
+ setup_warden_strategies
18
+ setup_warden_config
19
+ end
20
+
21
+ private
22
+ attr_reader :warden_config
23
+
24
+ def setup_warden_manager
25
+ Warden::Manager.serialize_into_session do |user|
26
+ user.id
27
+ end
11
28
 
12
- Warden::Strategies.add(:password_strategy, Monban::Strategies::PasswordStrategy)
29
+ Warden::Manager.serialize_from_session do |id|
30
+ Monban.config.user_class.find_by(id: id)
31
+ end
32
+ end
33
+
34
+ def setup_warden_strategies
35
+ Warden::Strategies.add(:password_strategy, Monban.config.authentication_strategy)
36
+ end
37
+
38
+ def setup_warden_config
39
+ warden_config.tap do |config|
40
+ config.failure_app = Monban.config.failure_app
41
+ end
42
+ end
43
+ end
44
+ end
data/lib/monban.rb CHANGED
@@ -56,8 +56,11 @@ module Monban
56
56
  # the user class
57
57
  #
58
58
  # @see Monban::Configuration#setup_class_defaults
59
+ # @deprecated Use Monban.config.user_class instead
59
60
  # @return [Class] the User class
60
61
  def self.user_class
62
+ warn "#{Kernel.caller.first}: [DEPRECATION] " +
63
+ 'Accessing the user class through the Monban module is deprecated. Use Monban.config.user_class instead.'
61
64
  config.user_class
62
65
  end
63
66
 
@@ -110,7 +113,6 @@ module Monban
110
113
  end
111
114
 
112
115
  def self.setup_warden_config(warden_config)
113
- warden_config.failure_app = self.config.failure_app
114
- self.warden_config = warden_config
116
+ self.warden_config = WardenSetup.new(warden_config).call
115
117
  end
116
118
  end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'User signs in through the back-door' do
4
+ scenario 'with the configured lookup field' do
5
+ user = User.create!
6
+
7
+ visit constrained_to_users_path(as: user)
8
+
9
+ expect(current_path).to eq constrained_to_users_path
10
+ end
11
+ end
@@ -105,13 +105,11 @@ module Monban
105
105
  end
106
106
 
107
107
  it 'returns false when it could not authenticate the user' do
108
- session_params = double()
109
- session_params.should_receive(:fetch).with(:password).and_return('password')
110
- session_params.should_receive(:except).with(:password).and_return(session_params)
108
+ session_params = { password: "password", lookup_key: "lookup_key" }
111
109
  user = double()
112
110
  authentication = double()
113
111
  authentication.should_receive(:perform).and_return(false)
114
- Monban.should_receive(:lookup).with(session_params, nil).and_return(user)
112
+ Monban.should_receive(:lookup).with({ lookup_key: "lookup_key" }, nil).and_return(user)
115
113
  Services::Authentication.should_receive(:new).with(user, 'password').and_return(authentication)
116
114
  @dummy.authenticate_session(session_params).should == false
117
115
  end
@@ -36,4 +36,14 @@ describe Monban::Services::SignUp, '#perform' do
36
36
  expect(args[:password_digest]).to be_nil
37
37
  end
38
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
+ Monban::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
39
49
  end
@@ -64,7 +64,7 @@ module Monban
64
64
 
65
65
  it 'performs a sign in' do
66
66
  user = double(id: 1)
67
- sign_in(user)
67
+ return_value = sign_in(user)
68
68
  app = lambda do |env|
69
69
  $captures << :run
70
70
  env['warden'].should be_authenticated
@@ -72,6 +72,8 @@ module Monban
72
72
  valid_response
73
73
  end
74
74
  setup_rack(app).call(env_with_params)
75
+
76
+ return_value.should eq(user)
75
77
  $captures.should eq([:run])
76
78
  end
77
79
 
@@ -1,5 +1,6 @@
1
1
  RailsApp::Application.configure do
2
2
  # Settings specified here will take precedence over those in config/application.rb
3
+ config.middleware.insert_after Warden::Manager, Monban::BackDoor
3
4
 
4
5
  # The test environment is used exclusively to run your application's
5
6
  # test suite. You never need to work with it otherwise. Remember that
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monban
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - halogenandtoast
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-07 00:00:00.000000000 Z
12
+ date: 2015-02-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -172,6 +172,7 @@ files:
172
172
  - lib/monban/version.rb
173
173
  - lib/monban/warden_setup.rb
174
174
  - monban.gemspec
175
+ - spec/features/user/user_signs_in_through_back_door_spec.rb
175
176
  - spec/features/user/user_tries_to_access_constrained_routes_spec.rb
176
177
  - spec/features/visitor/visitor_fails_to_sign_up_spec.rb
177
178
  - spec/features/visitor/visitor_is_unauthorized_spec.rb
@@ -254,6 +255,7 @@ signing_key:
254
255
  specification_version: 4
255
256
  summary: Making rails authentication as simple as possible
256
257
  test_files:
258
+ - spec/features/user/user_signs_in_through_back_door_spec.rb
257
259
  - spec/features/user/user_tries_to_access_constrained_routes_spec.rb
258
260
  - spec/features/visitor/visitor_fails_to_sign_up_spec.rb
259
261
  - spec/features/visitor/visitor_is_unauthorized_spec.rb
@@ -312,4 +314,3 @@ test_files:
312
314
  - spec/rails_app/public/favicon.ico
313
315
  - spec/rails_app/script/rails
314
316
  - spec/spec_helper.rb
315
- has_rdoc: