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 +4 -4
- data/Gemfile.lock +2 -2
- data/NEWS.rdoc +11 -0
- data/README.md +89 -0
- data/lib/monban/back_door.rb +14 -2
- data/lib/monban/configuration.rb +7 -5
- data/lib/monban/controller_helpers.rb +3 -2
- data/lib/monban/services/sign_up.rb +1 -1
- data/lib/monban/strategies/password_strategy.rb +1 -1
- data/lib/monban/test/helpers.rb +3 -0
- data/lib/monban/version.rb +2 -2
- data/lib/monban/warden_setup.rb +39 -7
- data/lib/monban.rb +4 -2
- data/spec/features/user/user_signs_in_through_back_door_spec.rb +11 -0
- data/spec/monban/controller_helpers_spec.rb +2 -4
- data/spec/monban/services/sign_up_spec.rb +10 -0
- data/spec/monban/test_helpers_spec.rb +3 -1
- data/spec/rails_app/config/environments/test.rb +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd09aa083126137a0de785ca3c26497485606236
|
4
|
+
data.tar.gz: c5280f21c291872564c4785f29951baa4292f541
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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:
|
data/lib/monban/back_door.rb
CHANGED
@@ -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 =
|
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
|
data/lib/monban/configuration.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
-
|
102
|
-
|
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
|
|
@@ -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
|
data/lib/monban/test/helpers.rb
CHANGED
data/lib/monban/version.rb
CHANGED
data/lib/monban/warden_setup.rb
CHANGED
@@ -1,12 +1,44 @@
|
|
1
1
|
require 'warden'
|
2
2
|
require "monban/strategies/password_strategy"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
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::
|
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
|
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 =
|
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(
|
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.
|
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:
|
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:
|