challah 1.6.1 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![
|
3
|
+
[![CircleCI](https://circleci.com/gh/jdtornow/challah.svg?style=svg)](https://circleci.com/gh/jdtornow/challah) [![Code Climate](https://codeclimate.com/github/jdtornow/challah/badges/gpa.svg)](https://codeclimate.com/github/jdtornow/challah) [![Gem Version](https://badge.fury.io/rb/challah.svg)](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
|