challah 1.6.1 → 2.0.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +5 -38
- data/VERSION +1 -1
- data/app/controllers/sessions_controller.rb +11 -10
- data/app/models/authorization.rb +2 -0
- data/lib/challah/audit.rb +38 -36
- data/lib/challah/authenticators/api_key.rb +4 -2
- data/lib/challah/authenticators/password.rb +3 -1
- data/lib/challah/authenticators.rb +5 -3
- data/lib/challah/concerns/authorizeable.rb +4 -0
- data/lib/challah/concerns/user/attributeable.rb +35 -33
- data/lib/challah/concerns/user/authenticateable.rb +2 -0
- data/lib/challah/concerns/user/authorizable.rb +16 -12
- data/lib/challah/concerns/user/findable.rb +13 -10
- data/lib/challah/concerns/user/passwordable.rb +5 -3
- data/lib/challah/concerns/user/provideable.rb +22 -20
- data/lib/challah/concerns/user/statusable.rb +3 -21
- data/lib/challah/concerns/user/validateable.rb +3 -1
- data/lib/challah/concerns/userable.rb +1 -3
- data/lib/challah/controller.rb +69 -65
- data/lib/challah/cookie_store.rb +7 -5
- data/lib/challah/encrypter.rb +4 -2
- data/lib/challah/engine.rb +5 -18
- data/lib/challah/providers/password_provider.rb +9 -7
- data/lib/challah/providers.rb +3 -1
- data/lib/challah/random.rb +6 -4
- data/lib/challah/routes.rb +6 -6
- data/lib/challah/session.rb +27 -25
- data/lib/challah/signup.rb +5 -3
- data/lib/challah/simple_cookie_store.rb +82 -80
- data/lib/challah/techniques/api_key_technique.rb +2 -2
- data/lib/challah/techniques/password_technique.rb +2 -1
- data/lib/challah/techniques/token_technique.rb +1 -1
- data/lib/challah/techniques.rb +2 -0
- data/lib/challah/test.rb +6 -0
- data/lib/challah/validators/email_validator.rb +2 -0
- data/lib/challah/validators/password_validator.rb +5 -3
- data/lib/challah/version.rb +3 -1
- data/lib/challah.rb +2 -5
- data/lib/generators/challah_generator.rb +2 -8
- data/lib/generators/templates/{migration.rb → migration.erb} +3 -6
- metadata +42 -19
- data/lib/challah/plugins.rb +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b260522736245710527baecf3c8060c67609feee2619eb460c36771350aa8ac
|
4
|
+
data.tar.gz: f94497f70a4ad972954284a54ebfe997757d5d08ae7c2dc320f947fc147731f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66bb3654fc8a8204075bb6e5645486a233a591eb57e37a20b3b979bab4961ab2b67c6b130479b977796eef88aadef49e4b7ec4b114b90fbbfcfac2809884234d
|
7
|
+
data.tar.gz: f93ed733130b3b69a128fde0cd8c4bc36e9989b4ac340410c72fa32b2e6498838860f4cc18e2c780adc3b2129d069efe3fe9e8be086c7f407770b39bcae4a16c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## Challah 2.0.0.beta1
|
2
|
+
|
3
|
+
This version introduces the following breaking changes, and therefore a new major version number:
|
4
|
+
|
5
|
+
* Plugins no longer supported. This was never fully baked and was only used for the now defunct challah-rolls library, which is no longer maintained.
|
6
|
+
* Drops support for Rails 4
|
7
|
+
* Drops support for Ruby prior to 2.5.0
|
8
|
+
* Removes legacy support for boolean-based User#active column in favor of enums on User#status
|
9
|
+
|
10
|
+
Plus the following new changes:
|
11
|
+
|
12
|
+
* Support for Rails 6.0
|
13
|
+
* Authorizations table is now properly set as a foreign key to users (for new installations only, for existing tables you can do this yourself)
|
14
|
+
|
1
15
|
## Challah 1.6.1
|
2
16
|
|
3
17
|
* Prevent an email address that is blank from saving the `User#email_hash` attribute
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Challah
|
2
2
|
|
3
|
-
[](https://circleci.com/gh/jdtornow/challah) [](https://codeclimate.com/github/jdtornow/challah) [](https://badge.fury.io/rb/challah)
|
4
4
|
|
5
5
|
Challah (pronounced HAH-lah) is a simple Rails authentication gem that provides users a way to authenticate with your app. Most of the functionality within the gem lives within a Rails engine and tries to stay out of the way of your app.
|
6
6
|
|
@@ -8,9 +8,8 @@ Challah doesn't provide any fancy controllers or views that clutter your app or
|
|
8
8
|
|
9
9
|
## Requirements
|
10
10
|
|
11
|
-
* Ruby 2.
|
12
|
-
*
|
13
|
-
* Rails 5.0+
|
11
|
+
* Ruby 2.5.0+
|
12
|
+
* Rails 5.2+
|
14
13
|
|
15
14
|
## Installation
|
16
15
|
|
@@ -35,7 +34,7 @@ This will copy over the necessary migrations to your app and migrate the databas
|
|
35
34
|
If you would prefer to handle these steps manually, you can do so by using these rake tasks instead:
|
36
35
|
|
37
36
|
```bash
|
38
|
-
rails
|
37
|
+
rails generate challah
|
39
38
|
rails challah:unpack:user
|
40
39
|
rails db:migrate
|
41
40
|
```
|
@@ -187,7 +186,7 @@ curl -H "X-App-User: abc123" \
|
|
187
186
|
|
188
187
|
_Note: Custom HTTP headers should always start with X-_
|
189
188
|
|
190
|
-
## ActionCable
|
189
|
+
## ActionCable
|
191
190
|
|
192
191
|
Challah works well with securing your ActionCable channels since Rails 5. Here is a sample `ApplicationCable::Connection` file to secure connections to a valid signed-in user:
|
193
192
|
|
@@ -215,38 +214,6 @@ module ApplicationCable
|
|
215
214
|
end
|
216
215
|
```
|
217
216
|
|
218
|
-
## Upgrading to Challah 1.4+
|
219
|
-
|
220
|
-
In Challah 1.4, the `active` boolean column changed to a `status` Rails enum with "active" as the default option. To upgrade a users table, use the following migration example:
|
221
|
-
|
222
|
-
```bash
|
223
|
-
rails g migration ConvertUsersActiveToEnum
|
224
|
-
```
|
225
|
-
|
226
|
-
```ruby
|
227
|
-
class ConvertUsersActiveToEnum < ActiveRecord::Migration
|
228
|
-
def up
|
229
|
-
add_column :users, :status, :integer, default: 0
|
230
|
-
|
231
|
-
say_with_time "Converting users to status enum" do
|
232
|
-
User.where(active: false).update_all(status: User.statuses[:inactive])
|
233
|
-
end
|
234
|
-
|
235
|
-
remove_column :users, :active
|
236
|
-
end
|
237
|
-
|
238
|
-
def down
|
239
|
-
add_column :users, :active, :boolean, default: true
|
240
|
-
|
241
|
-
say_with_time "Converting users to active boolean" do
|
242
|
-
User.where(status: User.statuses[:inactive]).update_all(active: false)
|
243
|
-
end
|
244
|
-
|
245
|
-
remove_column :users, :status
|
246
|
-
end
|
247
|
-
end
|
248
|
-
```
|
249
|
-
|
250
217
|
## User Validations
|
251
218
|
|
252
219
|
By default, the `first_name`, `last_name`, and `email` fields are required on the user model. If you'd prefer to add your own validations and leave the defaults off, you can use the following option within an initializer:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0.beta1
|
@@ -3,6 +3,7 @@ if File.exist?(Rails.root.join("controllers/application_controller"))
|
|
3
3
|
end
|
4
4
|
|
5
5
|
class SessionsController < (defined?(ApplicationController) ? ApplicationController : ActionController::Base)
|
6
|
+
|
6
7
|
before_action :destroy_session, except: :create
|
7
8
|
|
8
9
|
# GET /login
|
@@ -20,7 +21,7 @@ class SessionsController < (defined?(ApplicationController) ? ApplicationControl
|
|
20
21
|
if @session.save
|
21
22
|
redirect_to return_to_path
|
22
23
|
else
|
23
|
-
redirect_to signin_path, alert: I18n.translate(
|
24
|
+
redirect_to signin_path, alert: I18n.translate("sessions.create.failed_login")
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
@@ -32,14 +33,14 @@ class SessionsController < (defined?(ApplicationController) ? ApplicationControl
|
|
32
33
|
|
33
34
|
protected
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
def destroy_session
|
37
|
+
current_user_session.destroy
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
40
|
+
def return_to_path(default_path = "/")
|
41
|
+
result = session[:return_to]
|
42
|
+
result = nil if result && (result == "http://#{ request.domain }/")
|
43
|
+
result || default_path
|
44
|
+
end
|
45
45
|
|
46
|
+
end
|
data/app/models/authorization.rb
CHANGED
data/lib/challah/audit.rb
CHANGED
@@ -28,6 +28,7 @@ module Challah
|
|
28
28
|
# end
|
29
29
|
#
|
30
30
|
module Audit
|
31
|
+
|
31
32
|
extend ActiveSupport::Concern
|
32
33
|
|
33
34
|
included do
|
@@ -58,53 +59,54 @@ module Challah
|
|
58
59
|
|
59
60
|
private
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
def before_save_audit
|
63
|
+
if new_record?
|
64
|
+
all_audit_attributes.map(&:to_s).each do |column|
|
65
|
+
if respond_to?(column) && respond_to?("#{ column }=")
|
66
|
+
write_attribute(column, current_user_id)
|
67
|
+
end
|
66
68
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
else
|
70
|
+
audit_attributes_for_update.map(&:to_s).each do |column|
|
71
|
+
if respond_to?(column) && respond_to?("#{ column }=")
|
72
|
+
next if attribute_changed?(column) # don't update the column if we already manually did
|
73
|
+
write_attribute(column, current_user_id)
|
74
|
+
end
|
73
75
|
end
|
74
76
|
end
|
75
77
|
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# @private
|
79
|
-
def audit_attributes_for_update
|
80
|
-
[ :updated_by, :modifed_by, :updated_user_id ]
|
81
|
-
end
|
82
78
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
79
|
+
# @private
|
80
|
+
def audit_attributes_for_update
|
81
|
+
[ :updated_by, :modifed_by, :updated_user_id ]
|
82
|
+
end
|
87
83
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
84
|
+
# @private
|
85
|
+
def audit_attributes_for_create
|
86
|
+
[ :created_by, :created_user_id ]
|
87
|
+
end
|
92
88
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
if respond_to?(attribute_name) && respond_to?("#{ attribute_name }=")
|
97
|
-
write_attribute(attribute_name, nil)
|
98
|
-
end
|
89
|
+
# @private
|
90
|
+
def all_audit_attributes
|
91
|
+
audit_attributes_for_update + audit_attributes_for_create
|
99
92
|
end
|
100
93
|
|
101
|
-
|
102
|
-
|
103
|
-
|
94
|
+
# Clear attributes and changed_attributes
|
95
|
+
def clear_audit_attributes
|
96
|
+
all_audit_attributes.each do |attribute_name|
|
97
|
+
if respond_to?(attribute_name) && respond_to?("#{ attribute_name }=")
|
98
|
+
write_attribute(attribute_name, nil)
|
99
|
+
end
|
104
100
|
end
|
105
101
|
|
106
|
-
result
|
102
|
+
@changed_attributes = changed_attributes.reduce(ActiveSupport::HashWithIndifferentAccess.new) do |result, (key, value)|
|
103
|
+
unless all_audit_attributes.include?(key.to_sym)
|
104
|
+
result[key] = value
|
105
|
+
end
|
106
|
+
|
107
|
+
result
|
108
|
+
end
|
107
109
|
end
|
108
|
-
|
110
|
+
|
109
111
|
end
|
110
112
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Challah
|
2
2
|
module Authenticators
|
3
3
|
class Password
|
4
|
+
|
4
5
|
def self.match?(user, provider, plain_password)
|
5
6
|
if !!provider
|
6
7
|
crypted_password = provider.fetch(:token)
|
@@ -9,6 +10,7 @@ module Challah
|
|
9
10
|
|
10
11
|
false
|
11
12
|
end
|
13
|
+
|
12
14
|
end
|
13
15
|
end
|
14
|
-
end
|
16
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "challah/authenticators/api_key"
|
2
|
+
require "challah/authenticators/password"
|
3
3
|
|
4
4
|
module Challah
|
5
5
|
module Authenticators
|
6
|
+
|
6
7
|
# Register a new authenticator.
|
7
8
|
#
|
8
9
|
# Usage:
|
@@ -19,5 +20,6 @@ module Challah
|
|
19
20
|
def authenticators
|
20
21
|
@authenticators.dup
|
21
22
|
end
|
23
|
+
|
22
24
|
end
|
23
|
-
end
|
25
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Challah
|
2
2
|
module Authorizeable
|
3
|
+
|
3
4
|
extend ActiveSupport::Concern
|
4
5
|
|
5
6
|
included do
|
@@ -12,6 +13,7 @@ module Challah
|
|
12
13
|
end
|
13
14
|
|
14
15
|
module ClassMethods
|
16
|
+
|
15
17
|
def hashable_attributes
|
16
18
|
protected_attributes = %w( user_id provider last_session_at last_session_ip session_count created_at updated_at )
|
17
19
|
@hashable_attributes ||= self.columns.map(&:name) - protected_attributes
|
@@ -63,6 +65,8 @@ module Challah
|
|
63
65
|
def user_model
|
64
66
|
@user_model ||= Challah.user
|
65
67
|
end
|
68
|
+
|
66
69
|
end
|
70
|
+
|
67
71
|
end
|
68
72
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Challah
|
2
2
|
module UserAttributeable
|
3
|
+
|
3
4
|
extend ActiveSupport::Concern
|
4
5
|
|
5
6
|
included do
|
@@ -30,50 +31,51 @@ module Challah
|
|
30
31
|
|
31
32
|
protected
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
# Ensure that all system-generated columns aren't blank on each save
|
35
|
+
def ensure_user_tokens
|
36
|
+
ensure_api_key_presence
|
37
|
+
ensure_email_hash_presence
|
38
|
+
ensure_persistence_token_presence
|
39
|
+
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
# Store a random seed for this user's api key
|
42
|
+
def ensure_api_key_presence
|
43
|
+
if respond_to?("api_key=")
|
44
|
+
if self.api_key.to_s.blank?
|
45
|
+
self.api_key = Random.token(50)
|
46
|
+
end
|
45
47
|
end
|
46
48
|
end
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
# Store a hashed email if the column exists
|
51
|
+
def ensure_email_hash_presence
|
52
|
+
if respond_to?("email_hash=")
|
53
|
+
if email_changed?
|
54
|
+
self.email_hash = generate_email_hash
|
55
|
+
end
|
54
56
|
end
|
55
57
|
end
|
56
|
-
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
# Store a random token to identify user in persisted objects
|
60
|
+
def ensure_persistence_token_presence
|
61
|
+
if respond_to?("persistence_token=")
|
62
|
+
if self.persistence_token.to_s.blank?
|
63
|
+
self.persistence_token = Random.token(125)
|
64
|
+
end
|
63
65
|
end
|
64
66
|
end
|
65
|
-
end
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
def generate_email_hash
|
69
|
+
if self.email.present?
|
70
|
+
Encrypter.md5(email.to_s.downcase.strip)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Downcase email and strip if of whitespace
|
75
|
+
# Ex: " HELLO@example.com " => "hello@example.com"
|
76
|
+
def normalize_user_email
|
77
|
+
self.email = self.email.to_s.downcase.strip
|
70
78
|
end
|
71
|
-
end
|
72
79
|
|
73
|
-
# Downcase email and strip if of whitespace
|
74
|
-
# Ex: " HELLO@example.com " => "hello@example.com"
|
75
|
-
def normalize_user_email
|
76
|
-
self.email = self.email.to_s.downcase.strip
|
77
|
-
end
|
78
80
|
end
|
79
81
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Challah
|
2
2
|
module UserAuthenticateable
|
3
|
+
|
3
4
|
# Generic authentication method. By default, this just checks to see if the password
|
4
5
|
# given matches this user. You can also pass in the first parameter as the method
|
5
6
|
# to use for a different type of authentication.
|
@@ -39,5 +40,6 @@ module Challah
|
|
39
40
|
self.save
|
40
41
|
self.increment!(:session_count, 1)
|
41
42
|
end
|
43
|
+
|
42
44
|
end
|
43
45
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Challah
|
2
2
|
module UserAuthorizable
|
3
|
+
|
3
4
|
extend ActiveSupport::Concern
|
4
5
|
|
5
6
|
included do
|
@@ -8,25 +9,28 @@ module Challah
|
|
8
9
|
before_destroy :clear_authorizations_before_destroy
|
9
10
|
end
|
10
11
|
|
11
|
-
protected
|
12
|
-
|
13
12
|
def authorizations
|
14
13
|
return [] if new_record?
|
15
14
|
self.class.authorization_model.where(user_id: self.id)
|
16
15
|
end
|
17
16
|
|
18
|
-
|
19
|
-
authorizations.destroy_all
|
20
|
-
end
|
17
|
+
protected
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
@authorizations_table_name ||= authorization_model.table_name
|
19
|
+
def clear_authorizations_before_destroy
|
20
|
+
authorizations.destroy_all
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
23
|
+
module ClassMethods
|
24
|
+
|
25
|
+
def authorizations_table_name
|
26
|
+
@authorizations_table_name ||= authorization_model.table_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def authorization_model
|
30
|
+
@authorization_model ||= ::Authorization
|
31
|
+
end
|
32
|
+
|
29
33
|
end
|
30
|
-
|
34
|
+
|
31
35
|
end
|
32
|
-
end
|
36
|
+
end
|