veri 0.1.0 → 0.2.0
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 +12 -0
- data/README.md +52 -26
- data/lib/generators/veri/templates/add_veri_authentication.rb.erb +3 -0
- data/lib/veri/controllers/concerns/authentication.rb +6 -7
- data/lib/veri/models/concerns/authenticatable.rb +4 -1
- data/lib/veri/models/session.rb +25 -4
- data/lib/veri/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0782d4bd585ca9ca0aaa91cb51fe4b240d9e97ccf829c69890bc2079b38dda18'
|
4
|
+
data.tar.gz: 56cd6f6147a7b23ea2a5cc0b12dd9d573fcae55dcbf49462f93a4db59d5ef724
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29763c6104a41dd4987ff30d4c75089d8390d5c36afb7d9f9f297fe627380f0b674d46d4c52aedb27865776d6915bd38ca4acacc2adda7894fe66d9e457bfeec
|
7
|
+
data.tar.gz: '038ae16e36b31d87b4b83f7d51f51bb4c9d9318e6c161c9249f6eeff0a6a970343a2b1acbcb256edb4622bd03e01d1b6dda5c90c441274ef3b841f792dbc8ba6'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## v0.2.0
|
2
|
+
|
3
|
+
### Breaking
|
4
|
+
|
5
|
+
- Added `password_updated_at` timestamp tracking for authenticatable models
|
6
|
+
- Added shapeshifter functionality for impersonation/session switching
|
7
|
+
|
8
|
+
### Features
|
9
|
+
|
10
|
+
- Added `Session#identity` method
|
11
|
+
- Added `current_session` helper method for views
|
12
|
+
|
1
13
|
## v0.1.0
|
2
14
|
|
3
15
|
- Initial release
|
data/README.md
CHANGED
@@ -10,9 +10,8 @@ Veri is a cookie-based authentication library for Ruby on Rails that provides es
|
|
10
10
|
- Cookie-based authentication with database-stored sessions
|
11
11
|
- Supports multiple password hashing algorithms (argon2, bcrypt, scrypt)
|
12
12
|
- Granular session management and control
|
13
|
-
- Flexible authentication callbacks
|
14
|
-
- No pre-defined business logic, no views, controllers, or mailers — just the essential methods
|
15
13
|
- Built-in return path handling
|
14
|
+
- User impersonation feature
|
16
15
|
|
17
16
|
> ⚠️ **Development Notice**<br>
|
18
17
|
> Veri is functional but in early development. Breaking changes may occur in minor releases until v1.0!
|
@@ -99,11 +98,11 @@ Include the authentication module and configure protection:
|
|
99
98
|
class ApplicationController < ActionController::Base
|
100
99
|
include Veri::Authentication
|
101
100
|
|
102
|
-
with_authentication
|
101
|
+
with_authentication # Require authentication by default
|
103
102
|
end
|
104
103
|
|
105
104
|
class PicturesController < ApplicationController
|
106
|
-
skip_authentication only: [:index, :show]
|
105
|
+
skip_authentication only: [:index, :show] # Allow public access to index and show actions
|
107
106
|
end
|
108
107
|
```
|
109
108
|
|
@@ -136,16 +135,49 @@ end
|
|
136
135
|
|
137
136
|
Available methods:
|
138
137
|
|
139
|
-
- `current_user` -
|
140
|
-
- `logged_in?` -
|
141
|
-
- `log_in(user)` -
|
142
|
-
- `log_out` -
|
143
|
-
- `return_path` -
|
144
|
-
- `current_session` -
|
138
|
+
- `current_user` - Returns authenticated user or `nil`
|
139
|
+
- `logged_in?` - Returns `true` if user is authenticated
|
140
|
+
- `log_in(user)` - Authenticates user and creates session
|
141
|
+
- `log_out` - Terminates current session
|
142
|
+
- `return_path` - Returns path user was accessing before authentication
|
143
|
+
- `current_session` - Returns current authentication session
|
145
144
|
|
146
|
-
###
|
145
|
+
### User Impersonation (Shapeshifting)
|
147
146
|
|
148
|
-
|
147
|
+
Veri provides user impersonation functionality that allows, for example, administrators to temporarily assume another user's identity:
|
148
|
+
|
149
|
+
```rb
|
150
|
+
module Admin
|
151
|
+
class ImpersonationController < ApplicationController
|
152
|
+
def create
|
153
|
+
user = User.find(params[:user_id])
|
154
|
+
current_session.shapeshift(user)
|
155
|
+
redirect_to root_path, notice: "Now viewing as #{user.name}"
|
156
|
+
end
|
157
|
+
|
158
|
+
def destroy
|
159
|
+
original_user = current_session.true_identity
|
160
|
+
current_session.revert_to_true_identity
|
161
|
+
redirect_to admin_dashboard_path, notice: "Returned to #{original_user.name}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
Available session methods:
|
168
|
+
|
169
|
+
- `shapeshift(user)` - Assume another user's identity (maintains original identity)
|
170
|
+
- `revert_to_true_identity` - Return to original identity
|
171
|
+
- `shapeshifted?` - Returns true if currently shapeshifted
|
172
|
+
- `true_identity` - Returns original user when shapeshifted, otherwise current user
|
173
|
+
|
174
|
+
Controller helper:
|
175
|
+
|
176
|
+
- `shapeshifter?` - Returns true if the current session is shapeshifted
|
177
|
+
|
178
|
+
### When unauthenticated
|
179
|
+
|
180
|
+
Override this private method to customize authentication behavior:
|
149
181
|
|
150
182
|
```rb
|
151
183
|
class ApplicationController < ActionController::Base
|
@@ -157,18 +189,6 @@ class ApplicationController < ActionController::Base
|
|
157
189
|
|
158
190
|
private
|
159
191
|
|
160
|
-
# Called after successful login
|
161
|
-
def after_login(user)
|
162
|
-
Rails.logger.info "User #{user.id} logged in"
|
163
|
-
# Custom redirect logic, analytics, etc.
|
164
|
-
end
|
165
|
-
|
166
|
-
# Called after logout
|
167
|
-
def after_logout
|
168
|
-
Rails.logger.info "User logged out"
|
169
|
-
# Cleanup, analytics, etc.
|
170
|
-
end
|
171
|
-
|
172
192
|
# Customize unauthenticated user handling
|
173
193
|
def when_unauthenticated
|
174
194
|
# By default redirects back with a fallback to the root path if the request format is HTML,
|
@@ -180,7 +200,7 @@ end
|
|
180
200
|
|
181
201
|
## Authentication Sessions
|
182
202
|
|
183
|
-
Veri stores authentication sessions in the database,
|
203
|
+
Veri stores authentication sessions in the database, providing session management capabilities:
|
184
204
|
|
185
205
|
### Session Access
|
186
206
|
|
@@ -195,13 +215,15 @@ current_session
|
|
195
215
|
### Session Information
|
196
216
|
|
197
217
|
```rb
|
218
|
+
session.identity
|
219
|
+
# => authenticated user
|
198
220
|
session.info
|
199
221
|
# => {
|
200
222
|
# device: "Desktop",
|
201
223
|
# os: "macOS",
|
202
224
|
# browser: "Chrome",
|
203
225
|
# ip_address: "1.2.3.4",
|
204
|
-
#
|
226
|
+
# last_seen_at: "2023-10-01 12:00:00"
|
205
227
|
# }
|
206
228
|
```
|
207
229
|
|
@@ -234,6 +256,10 @@ Access authentication state in your views:
|
|
234
256
|
```erb
|
235
257
|
<% if logged_in? %>
|
236
258
|
<p>Welcome, <%= current_user.name %>!</p>
|
259
|
+
<% if shapeshifter? %>
|
260
|
+
<p><em>Currently viewing as <%= current_user.name %> (Original: <%= current_session.true_identity.name %>)</em></p>
|
261
|
+
<%= link_to "Return to Original Identity", revert_path, method: :patch %>
|
262
|
+
<% end %>
|
237
263
|
<%= link_to "Logout", logout_path, method: :delete %>
|
238
264
|
<% else %>
|
239
265
|
<%= link_to "Login", login_path %>
|
@@ -1,11 +1,14 @@
|
|
1
1
|
class AddVeriAuthentication < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version.to_s %>]
|
2
2
|
def change
|
3
3
|
add_column <%= table_name.to_sym.inspect %>, :hashed_password, :text
|
4
|
+
add_column <%= table_name.to_sym.inspect %>, :password_updated_at, :datetime
|
4
5
|
|
5
6
|
create_table :veri_sessions<%= ", id: :uuid" if options[:uuid] %> do |t|
|
6
7
|
t.string :hashed_token, null: false, index: { unique: true }
|
7
8
|
t.datetime :expires_at, null: false
|
8
9
|
t.belongs_to :authenticatable, null: false, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }, index: true<%= ", type: :uuid" if options[:uuid] %>
|
10
|
+
t.belongs_to :original_authenticatable, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }, index: true<%= ", type: :uuid" if options[:uuid] %>
|
11
|
+
t.datetime :shapeshifted_at
|
9
12
|
t.datetime :last_seen_at, null: false
|
10
13
|
t.string :ip_address
|
11
14
|
t.string :user_agent
|
@@ -5,7 +5,7 @@ module Veri
|
|
5
5
|
included do
|
6
6
|
include ActionController::Cookies unless self < ActionController::Cookies
|
7
7
|
|
8
|
-
helper_method(:current_user, :logged_in
|
8
|
+
helper_method(:current_user, :logged_in?, :shapeshifter?, :current_session) if respond_to?(:helper_method)
|
9
9
|
end
|
10
10
|
|
11
11
|
class_methods do
|
@@ -23,7 +23,7 @@ module Veri
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def current_user
|
26
|
-
@current_user ||= current_session&.
|
26
|
+
@current_user ||= current_session&.identity
|
27
27
|
end
|
28
28
|
|
29
29
|
def current_session
|
@@ -34,13 +34,11 @@ module Veri
|
|
34
34
|
def log_in(authenticatable)
|
35
35
|
token = Veri::Session.establish(Veri::Inputs.process(authenticatable, as: :authenticatable), request)
|
36
36
|
cookies.encrypted.permanent[:veri_token] = { value: token, httponly: true }
|
37
|
-
after_login
|
38
37
|
end
|
39
38
|
|
40
39
|
def log_out
|
41
40
|
current_session&.terminate
|
42
41
|
cookies.delete(:veri_token)
|
43
|
-
after_logout
|
44
42
|
end
|
45
43
|
|
46
44
|
def logged_in?
|
@@ -51,6 +49,10 @@ module Veri
|
|
51
49
|
cookies.signed[:veri_return_path]
|
52
50
|
end
|
53
51
|
|
52
|
+
def shapeshifter?
|
53
|
+
!!current_session&.shapeshifted?
|
54
|
+
end
|
55
|
+
|
54
56
|
private
|
55
57
|
|
56
58
|
def with_authentication
|
@@ -66,8 +68,5 @@ module Veri
|
|
66
68
|
def when_unauthenticated
|
67
69
|
request.format.html? ? redirect_back(fallback_location: root_path) : head(:unauthorized)
|
68
70
|
end
|
69
|
-
|
70
|
-
def after_login = nil
|
71
|
-
def after_logout = nil
|
72
71
|
end
|
73
72
|
end
|
@@ -11,7 +11,10 @@ module Veri
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def update_password(password)
|
14
|
-
update!(
|
14
|
+
update!(
|
15
|
+
hashed_password: hasher.create(Veri::Inputs.process(password, as: :string)),
|
16
|
+
password_updated_at: Time.current
|
17
|
+
)
|
15
18
|
end
|
16
19
|
|
17
20
|
def verify_password(password)
|
data/lib/veri/models/session.rb
CHANGED
@@ -4,11 +4,12 @@ module Veri
|
|
4
4
|
class Session < ActiveRecord::Base
|
5
5
|
self.table_name = "veri_sessions"
|
6
6
|
|
7
|
-
|
7
|
+
# rubocop:disable Rails/ReflectionClassName
|
8
|
+
belongs_to :authenticatable, class_name: Veri::Configuration.user_model_name
|
9
|
+
belongs_to :original_authenticatable, class_name: Veri::Configuration.user_model_name, optional: true
|
10
|
+
# rubocop:enable Rails/ReflectionClassName
|
8
11
|
|
9
|
-
def active?
|
10
|
-
!expired? && !inactive?
|
11
|
-
end
|
12
|
+
def active? = !expired? && !inactive?
|
12
13
|
|
13
14
|
def expired?
|
14
15
|
expires_at < Time.current
|
@@ -46,6 +47,26 @@ module Veri
|
|
46
47
|
}
|
47
48
|
end
|
48
49
|
|
50
|
+
def identity = authenticatable
|
51
|
+
def shapeshifted? = original_authenticatable.present?
|
52
|
+
def true_identity = original_authenticatable || authenticatable
|
53
|
+
|
54
|
+
def shapeshift(user)
|
55
|
+
update!(
|
56
|
+
shapeshifted_at: Time.current,
|
57
|
+
original_authenticatable: authenticatable,
|
58
|
+
authenticatable: Veri::Inputs.process(user, as: :authenticatable)
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def revert_to_true_identity
|
63
|
+
update!(
|
64
|
+
shapeshifted_at: nil,
|
65
|
+
authenticatable: original_authenticatable,
|
66
|
+
original_authenticatable: nil
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
49
70
|
class << self
|
50
71
|
def establish(authenticatable, request)
|
51
72
|
token = SecureRandom.hex(32)
|
data/lib/veri/version.rb
CHANGED