authentication-zero 2.8.3 → 2.9.1

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +6 -0
  5. data/authentication-zero-api.md +210 -0
  6. data/lib/authentication_zero/version.rb +1 -1
  7. data/lib/generators/authentication/authentication_generator.rb +52 -20
  8. data/lib/generators/authentication/templates/controllers/api/authentications/events_controller.rb.tt +5 -0
  9. data/lib/generators/authentication/templates/controllers/api/sessions_controller.rb.tt +1 -5
  10. data/lib/generators/authentication/templates/controllers/html/authentications/events_controller.rb.tt +5 -0
  11. data/lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt +1 -5
  12. data/lib/generators/authentication/templates/controllers/{omniauth_controller.rb.tt → html/sessions/omniauth_controller.rb.tt} +1 -5
  13. data/lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt +1 -1
  14. data/lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt +1 -5
  15. data/lib/generators/authentication/templates/erb/authentications/events/index.html.erb +33 -0
  16. data/lib/generators/authentication/templates/erb/sessions/new.html.erb.tt +1 -1
  17. data/lib/generators/authentication/templates/migrations/create_events_migration.rb.tt +12 -0
  18. data/lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt +2 -2
  19. data/lib/generators/authentication/templates/migrations/create_table_migration.rb.tt +7 -0
  20. data/lib/generators/authentication/templates/models/current.rb.tt +1 -0
  21. data/lib/generators/authentication/templates/models/event.rb.tt +8 -0
  22. data/lib/generators/authentication/templates/models/model.rb.tt +16 -4
  23. data/lib/generators/authentication/templates/models/session.rb.tt +15 -0
  24. data/lib/generators/authentication/templates/test_unit/controllers/api/identity/email_verifications_controller_test.rb.tt +1 -1
  25. data/lib/generators/authentication/templates/test_unit/controllers/api/identity/emails_controller_test.rb.tt +1 -1
  26. data/lib/generators/authentication/templates/test_unit/controllers/api/passwords_controller_test.rb.tt +1 -1
  27. data/lib/generators/authentication/templates/test_unit/controllers/api/sessions/sudos_controller_test.rb.tt +1 -1
  28. data/lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt +3 -3
  29. data/lib/generators/authentication/templates/test_unit/controllers/html/identity/email_verifications_controller_test.rb.tt +1 -1
  30. data/lib/generators/authentication/templates/test_unit/controllers/html/identity/emails_controller_test.rb.tt +1 -1
  31. data/lib/generators/authentication/templates/test_unit/controllers/html/passwords_controller_test.rb.tt +1 -1
  32. data/lib/generators/authentication/templates/test_unit/controllers/html/registrations_controller_test.rb.tt +1 -1
  33. data/lib/generators/authentication/templates/test_unit/controllers/html/sessions/sudos_controller_test.rb.tt +1 -1
  34. data/lib/generators/authentication/templates/test_unit/controllers/html/sessions_controller_test.rb.tt +3 -3
  35. metadata +9 -4
  36. data/lib/generators/authentication/templates/migrations/add_omniauth_migration.rb.tt +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c761cc8c78b6706041724ca6313bb115f8263036a5d4ea94e50ea30c8928ebc
4
- data.tar.gz: d9488244decbc2fbd95e4d46b6847d34b701b3f023c6bb37c26da19a67a7ab19
3
+ metadata.gz: 349df436a5358765a5f4537e5e37e79c566dfe575875f77380fe1a2eeb21096f
4
+ data.tar.gz: f017571edaa6c887bcdecf4ffa023cc7d86830e0fba4ba3c7ad6dbd8626bf952
5
5
  SHA512:
6
- metadata.gz: 9a09fd156b599aba36c0e27d6c96e07779fde672da91b2db7541d12ea2395f581114569f8036cd18cdf6a062d68b9cabacb543b76a5885aa4121a79768495831
7
- data.tar.gz: bbdcd461f3effa96d83ffb631defa701eb4b174bc3ada9ce6782e906b136ed2c7d45f8f5c2b56b80d8caa95326f5fbcfa637759c44b3a731c356b3adef56b819
6
+ metadata.gz: a70ba5553accd5f23b71ad58b58dd270f78636b28bca944decb062d16a31d83808a9dca86cd2b38f5f83317a6748c32ef25d3944613686ea215c05cdcc647dbe
7
+ data.tar.gz: 2506decfeaa1e126d0160d11d787577ecff6c8afa6b4a27930a01ac65b9cfca2fa7ccdc82392dc488dafee102ebe4419ce1422450400810efcf7437fe1578454
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## Authentication Zero 2.9.0 (March 2, 2022) ##
2
+
3
+ * Implement trackable
4
+
1
5
  ## Authentication Zero 2.8.0 (March 2, 2022) ##
2
6
 
3
7
  * Organize controllers in identity and sessions namespaces
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authentication-zero (2.8.3)
4
+ authentication-zero (2.9.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -20,7 +20,9 @@ The purpose of authentication zero is to generate a pre-built authentication sys
20
20
  - Send e-mail confirmation when your email has been changed
21
21
  - Send e-mail notification when someone has logged into your account
22
22
  - Manage multiple sessions & devices
23
+ - Activity log (--trackable)
23
24
  - Log out
25
+ - [API documentation](https://github.com/lazaronixon/authentication-zero/blob/master/authentication-zero-api.md)
24
26
 
25
27
  ## Security and best practices
26
28
 
@@ -73,6 +75,10 @@ Add these lines to your `app/views/home/index.html.erb`:
73
75
  <%= link_to "Devices & Sessions", sessions_path %>
74
76
  </div>
75
77
 
78
+ <div>
79
+ <%# link_to "Activity Log", authentications_events_path %>
80
+ </div>
81
+
76
82
  <br>
77
83
 
78
84
  <%= button_to "Log out", Current.session, method: :delete %>
@@ -0,0 +1,210 @@
1
+ # Authentication Zero API
2
+
3
+ This document describe the api endpoints available in authentication-zero.
4
+
5
+ ## Making a request
6
+
7
+ To make a sign in request for example, append sign_in to the base URL to form something like http://localhost:3000/sign_in, also notice you have to include the Content-Type header and the JSON data: In cURL, it looks like this:
8
+
9
+ ``` shell
10
+ curl -H "Authorization: Bearer $ACCESS_TOKEN" \
11
+ -H 'Content-Type: application/json' \
12
+ -H 'User-Agent: MyApp (yourname@example.com)' \
13
+ -d '{ "email": "lazaronixon@hotmail.com", "password": "secret", "password_confirmation": "secret" }' \
14
+ http://localhost:3000/sign_in
15
+ ```
16
+
17
+ ## API endpoints
18
+
19
+ - [Sign up](#sign-up)
20
+ - [Sign in](#sign-in)
21
+ - [Get your sessions](#get-your-sessions)
22
+ - [Get a session](#get-a-session)
23
+ - [Destroy a session](#destroy-a-session)
24
+ - [Execute sudo](#execute-sudo)
25
+ - [Update your password](#update-your-password)
26
+ - [Update your email](#update-your-email)
27
+ - [Send verification email](#send-verification-email)
28
+ - [Verify email](#verify-email)
29
+ - [Send password reset email](#send-password-reset-email)
30
+ - [Reset password](#reset-password)
31
+
32
+ ## Registrations
33
+
34
+ ### Sign up
35
+
36
+ * `POST /sign_up` creates a user on database.
37
+
38
+ ###### Example JSON Request
39
+
40
+ ``` json
41
+ {
42
+ "email": "lazaronixon@hotmail.com",
43
+ "password": "Secret1*2*3*4*5*6",
44
+ "password_confirmation": "Secret1*2*3*4*5*6"
45
+ }
46
+ ```
47
+
48
+ This endpoint will return `201 Created` with the current JSON representation of the user if the creation was a success.
49
+
50
+ ## Sessions
51
+
52
+ ### Sign in
53
+
54
+ * `POST /sign_in` creates a session on database.
55
+
56
+ ###### Example JSON Request
57
+
58
+ ``` json
59
+ {
60
+ "email": "lazaronixon@hotmail.com",
61
+ "password": "Secret1*2*3*4*5*6"
62
+ }
63
+ ```
64
+
65
+ This endpoint will return `201 Created` with the current JSON representation of the session if the creation was a success, also you will receive a `X-Session-Token` that you will use as your authorization token.
66
+
67
+
68
+ ### Get your sessions
69
+
70
+ * `GET /sessions` will return a list of sessions.
71
+
72
+ ###### Example JSON Response
73
+
74
+ ``` json
75
+ [
76
+ {
77
+ "id": 2,
78
+ "user_id": 1,
79
+ "user_agent": "insomnia/2022.1.0",
80
+ "ip_address": "127.0.0.1",
81
+ "sudo_at": "2022-03-04T17:20:33.632Z",
82
+ "created_at": "2022-03-04T17:20:33.632Z",
83
+ "updated_at": "2022-03-04T17:20:33.632Z"
84
+ },
85
+ {
86
+ "id": 1,
87
+ "user_id": 1,
88
+ "user_agent": "insomnia/2022.1.0",
89
+ "ip_address": "127.0.0.1",
90
+ "sudo_at": "2022-03-04T17:14:03.386Z",
91
+ "created_at": "2022-03-04T17:14:03.386Z",
92
+ "updated_at": "2022-03-04T17:14:03.386Z"
93
+ }
94
+ ]
95
+ ```
96
+
97
+ ### Get a session
98
+
99
+ * `GET /sessions/1` will return the session with an ID of 1.
100
+
101
+ ###### Example JSON Response
102
+
103
+ ``` json
104
+ {
105
+ "id": 1,
106
+ "user_id": 1,
107
+ "user_agent": "insomnia/2022.1.0",
108
+ "ip_address": "127.0.0.1",
109
+ "sudo_at": "2022-03-04T17:14:03.386Z",
110
+ "created_at": "2022-03-04T17:14:03.386Z",
111
+ "updated_at": "2022-03-04T17:14:03.386Z"
112
+ }
113
+ ```
114
+
115
+ ### Destroy a session
116
+
117
+ * `DELETE /sessions/1` will destroy the session with an ID of 1.
118
+
119
+ Returns `204 No Content` if successful.
120
+
121
+
122
+ ### Execute sudo
123
+
124
+ * `POST /sessions/sudo` will grant temporary access to sensitive information.
125
+
126
+ ###### Example JSON Request
127
+
128
+ ``` json
129
+ {
130
+ "password": "Secret1*2*3*4*5*6",
131
+ }
132
+ ```
133
+
134
+ Returns `204 No Content` if successful.
135
+
136
+ ## Password
137
+
138
+ ### Update your password
139
+
140
+ * `PUT /password` allows changing your password.
141
+
142
+ ###### Example JSON Request
143
+
144
+ ``` json
145
+ {
146
+ "current_password": "Secret1*2*3*4*5*6",
147
+ "password": "NewPassword12$34$56$7",
148
+ "password_confirmation": "NewPassword12$34$56$7"
149
+ }
150
+ ```
151
+
152
+ This endpoint will return 200 OK with the current JSON representation of the user if the update was a success.
153
+
154
+ ## Email
155
+
156
+ ### Update your email
157
+
158
+ * `PUT /identity/email` allows changing your email. **(requires sudo)**.
159
+
160
+ ###### Example JSON Request
161
+
162
+ ``` json
163
+ {
164
+ "email": "new_email@hey.com"
165
+ }
166
+ ```
167
+
168
+ This endpoint will return 200 OK with the current JSON representation of the user if the update was a success.
169
+
170
+ ## Email verification
171
+
172
+ ### Send verification email
173
+
174
+ * `POST /identity/email_verification` sends an email verification with the instructions and link to proceed with the verification.
175
+
176
+ Returns `204 No Content` if successful.
177
+
178
+ ### Verify email
179
+
180
+ * `GET /identity/email_verification` verify your email using a temporary token.
181
+
182
+ **Required parameters:** `email` and `token`.
183
+
184
+ Example: `/identity/email_verification?email=lazaronixon@hotmail.com&token=eyJfcmFpbHMiOnsibWVzc2FnZSI6Ik1nPT0iLCJleHAiOm51bGwsInB1ciI6InNlc3Npb24ifX0=--1a277b4a5576c6e371144a22476979a18d3e45fb8515a79e815cd4b95eb5fb6b`
185
+
186
+ Returns `204 No Content` if successful.
187
+
188
+ ## Password reset
189
+
190
+ ### Send password reset email
191
+
192
+ * `POST /identity/password_reset` sends a password reset email with the instructions and link to proceed reset.
193
+
194
+ Returns `204 No Content` if successful.
195
+
196
+ ### Reset password
197
+
198
+ * `PUT /identity/password_reset` allows changing your password through a email token.
199
+
200
+ ##### Example JSON Request
201
+
202
+ ``` json
203
+ {
204
+ "password": "NewPassword12$34$56$7",
205
+ "password_confirmation": "NewPassword12$34$56$7",
206
+ "token": "eyJfcmFpbHMiOnsibWVzc2FnZSI6Ik1nPT0iLCJleHAiOm51bGwsInB1ciI6InNlc3Npb24ifX0=--1a277b4a5576c6e371144a22476979a18d3e45fb8515a79e815cd4b95eb5fb6b",
207
+ }
208
+ ```
209
+
210
+ This endpoint will return 200 OK with the current JSON representation of the user if the update was a success.
@@ -1,3 +1,3 @@
1
1
  module AuthenticationZero
2
- VERSION = "2.8.3"
2
+ VERSION = "2.9.1"
3
3
  end
@@ -8,6 +8,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
8
8
  class_option :lockable, type: :boolean, desc: "Add password reset locking"
9
9
  class_option :ratelimit, type: :boolean, desc: "Add request rate limiting"
10
10
  class_option :omniauthable, type: :boolean, desc: "Add social login support"
11
+ class_option :trackable, type: :boolean, desc: "Add activity log support"
11
12
 
12
13
  source_root File.expand_path("templates", __dir__)
13
14
 
@@ -47,7 +48,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
47
48
  def create_migrations
48
49
  migration_template "migrations/create_table_migration.rb", "#{db_migrate_path}/create_#{table_name}.rb"
49
50
  migration_template "migrations/create_sessions_migration.rb", "#{db_migrate_path}/create_sessions.rb"
50
- migration_template "migrations/add_omniauth_migration.rb", "#{db_migrate_path}/add_omniauth_to_#{table_name}.rb" if omniauthable?
51
+ migration_template "migrations/create_events_migration.rb", "#{db_migrate_path}/create_events.rb" if options.trackable?
51
52
  end
52
53
 
53
54
  def create_models
@@ -55,6 +56,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
55
56
  template "models/session.rb", "app/models/session.rb"
56
57
  template "models/current.rb", "app/models/current.rb"
57
58
  template "models/locking.rb", "app/models/locking.rb" if options.lockable?
59
+ template "models/event.rb", "app/models/event.rb" if options.trackable?
58
60
  end
59
61
 
60
62
  def create_fixture_file
@@ -65,39 +67,53 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
65
67
  api_code = <<~CODE
66
68
  include ActionController::HttpAuthentication::Token::ControllerMethods
67
69
 
70
+ before_action :set_current_request_details
68
71
  before_action :authenticate
69
72
 
70
- def authenticate
71
- if session = authenticate_with_http_token { |token, _| Session.find_signed(token) }
72
- Current.session = session
73
- else
74
- request_http_token_authentication
75
- end
76
- end
77
-
78
73
  def require_sudo
79
74
  if Current.session.sudo_at < 30.minutes.ago
80
75
  render json: { error: "Enter your password to continue" }, status: :forbidden
81
76
  end
82
77
  end
78
+
79
+ private
80
+ def authenticate
81
+ if session = authenticate_with_http_token { |token, _| Session.find_signed(token) }
82
+ Current.session = session
83
+ else
84
+ request_http_token_authentication
85
+ end
86
+ end
87
+
88
+ def set_current_request_details
89
+ Current.user_agent = request.user_agent
90
+ Current.ip_address = request.ip
91
+ end
83
92
  CODE
84
93
 
85
94
  html_code = <<~CODE
95
+ before_action :set_current_request_details
86
96
  before_action :authenticate
87
97
 
88
- def authenticate
89
- if session = Session.find_by_id(cookies.signed[:session_token])
90
- Current.session = session
91
- else
92
- redirect_to sign_in_path
93
- end
94
- end
95
-
96
98
  def require_sudo
97
99
  if Current.session.sudo_at < 30.minutes.ago
98
100
  redirect_to new_sessions_sudo_path(proceed_to_url: request.url)
99
101
  end
100
102
  end
103
+
104
+ private
105
+ def authenticate
106
+ if session = Session.find_by_id(cookies.signed[:session_token])
107
+ Current.session = session
108
+ else
109
+ redirect_to sign_in_path
110
+ end
111
+ end
112
+
113
+ def set_current_request_details
114
+ Current.user_agent = request.user_agent
115
+ Current.ip_address = request.ip
116
+ end
101
117
  CODE
102
118
 
103
119
  inject_code = options.api? ? api_code : html_code
@@ -105,8 +121,13 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
105
121
  end
106
122
 
107
123
  def create_controllers
108
- directory "controllers/#{format_folder}", "app/controllers"
109
- template "controllers/omniauth_controller.rb", "app/controllers/sessions/omniauth_controller.rb" if omniauthable?
124
+ directory "controllers/#{format_folder}/identity", "app/controllers/identity"
125
+ template "controllers/#{format_folder}/passwords_controller.rb", "app/controllers/passwords_controller.rb"
126
+ template "controllers/#{format_folder}/registrations_controller.rb", "app/controllers/registrations_controller.rb"
127
+ template "controllers/#{format_folder}/sessions_controller.rb", "app/controllers/sessions_controller.rb"
128
+ template "controllers/#{format_folder}/sessions/sudos_controller.rb", "app/controllers/sessions/sudos_controller.rb"
129
+ template "controllers/#{format_folder}/sessions/omniauth_controller.rb", "app/controllers/sessions/omniauth_controller.rb" if omniauthable?
130
+ template "controllers/#{format_folder}/authentications/events_controller.rb", "app/controllers/authentications/events_controller.rb" if options.trackable?
110
131
  end
111
132
 
112
133
  def create_views
@@ -114,7 +135,14 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
114
135
  directory "erb/identity_mailer", "app/views/identity_mailer"
115
136
  directory "erb/session_mailer", "app/views/session_mailer"
116
137
  else
117
- directory "erb", "app/views"
138
+ directory "erb/identity_mailer", "app/views/identity_mailer"
139
+ directory "erb/session_mailer", "app/views/session_mailer"
140
+
141
+ directory "erb/identity", "app/views/identity"
142
+ directory "erb/passwords", "app/views/passwords"
143
+ directory "erb/registrations", "app/views/registrations"
144
+ directory "erb/sessions", "app/views/sessions"
145
+ directory "erb/authentications/events", "app/views/authentications/events" if options.trackable?
118
146
  end
119
147
  end
120
148
 
@@ -129,6 +157,10 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
129
157
  route "get '/auth/failure', to: 'sessions/omniauth#failure'"
130
158
  end
131
159
 
160
+ if options.trackable?
161
+ route "resources :events, only: :index", namespace: :authentications
162
+ end
163
+
132
164
  route "resource :password_reset, only: [:new, :edit, :create, :update]", namespace: :identity
133
165
  route "resource :email_verification, only: [:edit, :create]", namespace: :identity
134
166
  route "resource :email, only: [:edit, :update]", namespace: :identity
@@ -0,0 +1,5 @@
1
+ class Authentications::EventsController < ApplicationController
2
+ def index
3
+ render json: Current.<%= singular_table_name %>.events.order(created_at: :desc)
4
+ end
5
+ end
@@ -15,7 +15,7 @@ class SessionsController < ApplicationController
15
15
  <%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email])
16
16
 
17
17
  if <%= singular_table_name %> && <%= singular_table_name %>.authenticate(params[:password])
18
- @session = <%= singular_table_name %>.sessions.create!(session_params)
18
+ @session = <%= singular_table_name %>.sessions.create!
19
19
  response.set_header("X-Session-Token", @session.signed_id)
20
20
 
21
21
  render json: @session, status: :created
@@ -32,8 +32,4 @@ class SessionsController < ApplicationController
32
32
  def set_session
33
33
  @session = Current.<%= singular_table_name %>.sessions.find(params[:id])
34
34
  end
35
-
36
- def session_params
37
- { user_agent: request.user_agent, ip_address: request.remote_ip, sudo_at: Time.current }
38
- end
39
35
  end
@@ -0,0 +1,5 @@
1
+ class Authentications::EventsController < ApplicationController
2
+ def index
3
+ @events = Current.<%= singular_table_name %>.events.order(created_at: :desc)
4
+ end
5
+ end
@@ -9,7 +9,7 @@ class RegistrationsController < ApplicationController
9
9
  @<%= singular_table_name %> = <%= class_name %>.new(<%= "#{singular_table_name}_params" %>)
10
10
 
11
11
  if @<%= singular_table_name %>.save
12
- session = @<%= singular_table_name %>.sessions.create!(session_params)
12
+ session = @<%= singular_table_name %>.sessions.create!
13
13
  cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
14
14
 
15
15
  redirect_to root_path, notice: "Welcome! You have signed up successfully"
@@ -22,8 +22,4 @@ class RegistrationsController < ApplicationController
22
22
  def <%= "#{singular_table_name}_params" %>
23
23
  params.permit(:email, :password, :password_confirmation)
24
24
  end
25
-
26
- def session_params
27
- { user_agent: request.user_agent, ip_address: request.remote_ip, sudo_at: Time.current }
28
- end
29
25
  end
@@ -6,7 +6,7 @@ class Sessions::OmniauthController < ApplicationController
6
6
  @<%= singular_table_name %> = <%= class_name %>.where(omniauth_params).first_or_initialize(<%= "#{singular_table_name}_params" %>)
7
7
 
8
8
  if @<%= singular_table_name %>.save
9
- session = @<%= singular_table_name %>.sessions.create!(session_params)
9
+ session = @<%= singular_table_name %>.sessions.create!
10
10
  cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
11
11
 
12
12
  redirect_to root_path, notice: "Signed in successfully"
@@ -28,10 +28,6 @@ class Sessions::OmniauthController < ApplicationController
28
28
  { email: omniauth.info.email, password: SecureRandom::base58, verified: true }
29
29
  end
30
30
 
31
- def session_params
32
- { user_agent: request.user_agent, ip_address: request.remote_ip, sudo_at: Time.current }
33
- end
34
-
35
31
  def omniauth
36
32
  request.env["omniauth.auth"]
37
33
  end
@@ -5,7 +5,7 @@ class Sessions::SudosController < ApplicationController
5
5
  def create
6
6
  session = Current.session
7
7
 
8
- <% if options.omniauth? -%>
8
+ <% if omniauthable? -%>
9
9
  if session.<%= singular_table_name %>.authenticate(params[:password]) || session.<%= singular_table_name %>.provider
10
10
  <% else -%>
11
11
  if session.<%= singular_table_name %>.authenticate(params[:password])
@@ -15,7 +15,7 @@ class SessionsController < ApplicationController
15
15
  <%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email])
16
16
 
17
17
  if <%= singular_table_name %> && <%= singular_table_name %>.authenticate(params[:password])
18
- @session = <%= singular_table_name %>.sessions.create!(session_params)
18
+ @session = <%= singular_table_name %>.sessions.create!
19
19
  cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
20
20
 
21
21
  redirect_to root_path, notice: "Signed in successfully"
@@ -32,8 +32,4 @@ class SessionsController < ApplicationController
32
32
  def set_session
33
33
  @session = Current.<%= singular_table_name %>.sessions.find(params[:id])
34
34
  end
35
-
36
- def session_params
37
- { user_agent: request.user_agent, ip_address: request.remote_ip, sudo_at: Time.current }
38
- end
39
35
  end
@@ -0,0 +1,33 @@
1
+ <h1>Activity Log</h1>
2
+
3
+ <div id="sessions">
4
+ <% @events.each do |event| %>
5
+ <div id="<%= dom_id event %>">
6
+ <p>
7
+ <strong>User Agent:</strong>
8
+ <%= event.user_agent %>
9
+ </p>
10
+
11
+ <p>
12
+ <strong>Action:</strong>
13
+ <%= event.action %>
14
+ </p>
15
+
16
+ <p>
17
+ <strong>Ip Address:</strong>
18
+ <%= event.ip_address %>
19
+ </p>
20
+
21
+ <p>
22
+ <strong>Created at:</strong>
23
+ <%= event.created_at %>
24
+ </p>
25
+ </div>
26
+ <% end %>
27
+ </div>
28
+
29
+ <br>
30
+
31
+ <div>
32
+ <%= link_to "Back", root_path %>
33
+ </div>
@@ -18,7 +18,7 @@
18
18
  <%%= form.submit "Sign in" %>
19
19
  </div>
20
20
  <%% end %>
21
- <% if options.omniauth? %>
21
+ <% if omniauthable? %>
22
22
  <div>
23
23
  <%%= button_to "Sign in with OmniAuth", "/auth/developer", "data-turbo" => false %>
24
24
  </div>
@@ -0,0 +1,12 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :events do |t|
4
+ t.references :<%= singular_table_name %>, null: false, foreign_key: true
5
+ t.string :action, null: false
6
+ t.string :user_agent
7
+ t.string :ip_address
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -3,8 +3,8 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
3
3
  create_table :sessions do |t|
4
4
  t.references :<%= singular_table_name %>, null: false, foreign_key: true
5
5
 
6
- t.string :user_agent, null: false
7
- t.string :ip_address, null: false
6
+ t.string :user_agent
7
+ t.string :ip_address
8
8
 
9
9
  t.datetime :sudo_at, null: false
10
10
 
@@ -5,10 +5,17 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
5
5
  t.string :password_digest, null: false
6
6
 
7
7
  t.boolean :verified, null: false, default: false
8
+ <% if omniauthable? %>
9
+ t.string :provider
10
+ t.string :uid
11
+ <% end -%>
8
12
 
9
13
  t.timestamps
10
14
  end
11
15
 
12
16
  add_index :<%= table_name %>, :email, unique: true
17
+ <% if omniauthable? -%>
18
+ add_index :<%= table_name %>, [:provider, :uid], unique: true
19
+ <% end -%>
13
20
  end
14
21
  end
@@ -1,5 +1,6 @@
1
1
  class Current < ActiveSupport::CurrentAttributes
2
2
  attribute :session, :<%= singular_table_name %>
3
+ attribute :user_agent, :ip_address
3
4
 
4
5
  def session=(session)
5
6
  super; self.<%= singular_table_name %> = session.<%= singular_table_name %>
@@ -0,0 +1,8 @@
1
+ class Event < ApplicationRecord
2
+ belongs_to :<%= singular_table_name %>
3
+
4
+ before_create do
5
+ self.user_agent = Current.user_agent
6
+ self.ip_address = Current.ip_address
7
+ end
8
+ end
@@ -2,6 +2,9 @@ class <%= class_name %> < ApplicationRecord
2
2
  has_secure_password
3
3
 
4
4
  has_many :sessions, dependent: :destroy
5
+ <% if options.trackable? -%>
6
+ has_many :events, dependent: :destroy
7
+ <% end -%>
5
8
 
6
9
  validates :email, presence: true, uniqueness: true
7
10
  validates_format_of :email, with: /\A[^@\s]+@[^@\s]+\z/
@@ -24,11 +27,20 @@ class <%= class_name %> < ApplicationRecord
24
27
  sessions.where.not(id: Current.session).destroy_all
25
28
  end
26
29
 
27
- after_create_commit do
28
- IdentityMailer.with(<%= singular_table_name %>: self).email_verify_confirmation.deliver_later
30
+ after_save_commit if: :email_previously_changed? do
31
+ IdentityMailer.with(user: self).email_verify_confirmation.deliver_later
32
+ end
33
+ <% if options.trackable? %>
34
+ after_save_commit if: :email_previously_changed? do
35
+ events.create! action: "email_verification_requested"
36
+ end
37
+
38
+ after_update if: :password_digest_previously_changed? do
39
+ events.create! action: "password_changed"
29
40
  end
30
41
 
31
- after_update_commit if: :email_previously_changed? do
32
- IdentityMailer.with(<%= singular_table_name %>: self).email_verify_confirmation.deliver_later
42
+ after_update if: :verified_previously_changed? do
43
+ events.create! action: "email_verified" if verified?
33
44
  end
45
+ <% end -%>
34
46
  end
@@ -1,7 +1,22 @@
1
1
  class Session < ApplicationRecord
2
2
  belongs_to :<%= singular_table_name %>
3
3
 
4
+ before_create do
5
+ self.user_agent = Current.user_agent
6
+ self.ip_address = Current.ip_address
7
+ self.sudo_at = Time.current
8
+ end
9
+
4
10
  after_create_commit do
5
11
  SessionMailer.with(session: self).signed_in_notification.deliver_later
6
12
  end
13
+ <% if options.trackable? %>
14
+ after_create do
15
+ <%= singular_table_name %>.events.create! action: "signed_in"
16
+ end
17
+
18
+ after_destroy do
19
+ <%= singular_table_name %>.events.create! action: "signed_out"
20
+ end
21
+ <% end -%>
7
22
  end
@@ -39,6 +39,6 @@ class Identity::EmailVerificationsControllerTest < ActionDispatch::IntegrationTe
39
39
  end
40
40
 
41
41
  def sign_in_as(<%= singular_table_name %>)
42
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "App iOS" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
42
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
43
43
  end
44
44
  end
@@ -20,6 +20,6 @@ class Identity::EmailsControllerTest < ActionDispatch::IntegrationTest
20
20
  end
21
21
 
22
22
  def sign_in_as(<%= singular_table_name %>)
23
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "App iOS" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
23
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
24
24
  end
25
25
  end
@@ -18,6 +18,6 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
18
18
  end
19
19
 
20
20
  def sign_in_as(<%= singular_table_name %>)
21
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "App iOS" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
21
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
22
22
  end
23
23
  end
@@ -19,6 +19,6 @@ class Sessions::SudosControllerTest < ActionDispatch::IntegrationTest
19
19
  end
20
20
 
21
21
  def sign_in_as(<%= singular_table_name %>)
22
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "App iOS" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
22
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
23
23
  end
24
24
  end
@@ -16,14 +16,14 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
16
16
  end
17
17
 
18
18
  test "should sign in" do
19
- post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "App iOS" }
19
+ post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "Secret1*3*5*" }
20
20
 
21
21
  assert_enqueued_email_with SessionMailer, :signed_in_notification, args: { session: @<%= singular_table_name %>.sessions.last }
22
22
  assert_response :created
23
23
  end
24
24
 
25
25
  test "should not sign in with wrong credentials" do
26
- post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "SecretWrong1*3" }, headers: { "User-Agent" => "App iOS" }
26
+ post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "SecretWrong1*3" }
27
27
  assert_response :unauthorized
28
28
  end
29
29
 
@@ -33,6 +33,6 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
33
33
  end
34
34
 
35
35
  def sign_in_as(<%= singular_table_name %>)
36
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "App iOS" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
36
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
37
37
  end
38
38
  end
@@ -39,6 +39,6 @@ class Identity::EmailVerificationsControllerTest < ActionDispatch::IntegrationTe
39
39
  end
40
40
 
41
41
  def sign_in_as(<%= singular_table_name %>)
42
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "Firefox" }); <%= singular_table_name %>
42
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
43
43
  end
44
44
  end
@@ -30,6 +30,6 @@ class Identity::EmailsControllerTest < ActionDispatch::IntegrationTest
30
30
  end
31
31
 
32
32
  def sign_in_as(<%= singular_table_name %>)
33
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "Firefox" }); <%= singular_table_name %>
33
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
34
34
  end
35
35
  end
@@ -23,6 +23,6 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
23
23
  end
24
24
 
25
25
  def sign_in_as(<%= singular_table_name %>)
26
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "Firefox" }); <%= singular_table_name %>
26
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
27
27
  end
28
28
  end
@@ -8,7 +8,7 @@ class RegistrationsControllerTest < ActionDispatch::IntegrationTest
8
8
 
9
9
  test "should sign up" do
10
10
  assert_difference("<%= class_name %>.count") do
11
- post sign_up_url, params: { email: "lazaronixon@hey.com", password: "Secret1*3*5*", password_confirmation: "Secret1*3*5*" }, headers: { "User-Agent" => "Firefox" }
11
+ post sign_up_url, params: { email: "lazaronixon@hey.com", password: "Secret1*3*5*", password_confirmation: "Secret1*3*5*" }
12
12
  end
13
13
 
14
14
  assert_redirected_to root_url
@@ -21,6 +21,6 @@ class Sessions::SudosControllerTest < ActionDispatch::IntegrationTest
21
21
  end
22
22
 
23
23
  def sign_in_as(<%= singular_table_name %>)
24
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "Firefox" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
24
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
25
25
  end
26
26
  end
@@ -18,7 +18,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
18
18
  end
19
19
 
20
20
  test "should sign in" do
21
- post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "Firefox" }
21
+ post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "Secret1*3*5*" }
22
22
  assert_enqueued_email_with SessionMailer, :signed_in_notification, args: { session: @<%= singular_table_name %>.sessions.last }
23
23
 
24
24
  assert_redirected_to root_url
@@ -28,7 +28,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
28
28
  end
29
29
 
30
30
  test "should not sign in with wrong credentials" do
31
- post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "SecretWrong1*3" }, headers: { "User-Agent" => "Firefox" }
31
+ post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "SecretWrong1*3" }
32
32
  assert_redirected_to sign_in_url(email_hint: @<%= singular_table_name %>.email)
33
33
  assert_equal "That email or password is incorrect", flash[:alert]
34
34
 
@@ -47,6 +47,6 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
47
47
  end
48
48
 
49
49
  def sign_in_as(<%= singular_table_name %>)
50
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }, headers: { "User-Agent" => "Firefox" }); <%= singular_table_name %>
50
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
51
51
  end
52
52
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authentication-zero
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.3
4
+ version: 2.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nixon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-03 00:00:00.000000000 Z
11
+ date: 2022-03-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -26,6 +26,7 @@ files:
26
26
  - LICENSE.txt
27
27
  - README.md
28
28
  - Rakefile
29
+ - authentication-zero-api.md
29
30
  - authentication-zero.gemspec
30
31
  - lib/authentication-zero.rb
31
32
  - lib/authentication_zero.rb
@@ -34,6 +35,7 @@ files:
34
35
  - lib/generators/authentication/authentication_generator.rb
35
36
  - lib/generators/authentication/templates/config/initializers/omniauth.rb
36
37
  - lib/generators/authentication/templates/config/redis/shared.yml
38
+ - lib/generators/authentication/templates/controllers/api/authentications/events_controller.rb.tt
37
39
  - lib/generators/authentication/templates/controllers/api/identity/email_verifications_controller.rb.tt
38
40
  - lib/generators/authentication/templates/controllers/api/identity/emails_controller.rb.tt
39
41
  - lib/generators/authentication/templates/controllers/api/identity/password_resets_controller.rb.tt
@@ -41,14 +43,16 @@ files:
41
43
  - lib/generators/authentication/templates/controllers/api/registrations_controller.rb.tt
42
44
  - lib/generators/authentication/templates/controllers/api/sessions/sudos_controller.rb.tt
43
45
  - lib/generators/authentication/templates/controllers/api/sessions_controller.rb.tt
46
+ - lib/generators/authentication/templates/controllers/html/authentications/events_controller.rb.tt
44
47
  - lib/generators/authentication/templates/controllers/html/identity/email_verifications_controller.rb.tt
45
48
  - lib/generators/authentication/templates/controllers/html/identity/emails_controller.rb.tt
46
49
  - lib/generators/authentication/templates/controllers/html/identity/password_resets_controller.rb.tt
47
50
  - lib/generators/authentication/templates/controllers/html/passwords_controller.rb.tt
48
51
  - lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt
52
+ - lib/generators/authentication/templates/controllers/html/sessions/omniauth_controller.rb.tt
49
53
  - lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
50
54
  - lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt
51
- - lib/generators/authentication/templates/controllers/omniauth_controller.rb.tt
55
+ - lib/generators/authentication/templates/erb/authentications/events/index.html.erb
52
56
  - lib/generators/authentication/templates/erb/identity/emails/edit.html.erb.tt
53
57
  - lib/generators/authentication/templates/erb/identity/password_resets/edit.html.erb.tt
54
58
  - lib/generators/authentication/templates/erb/identity/password_resets/new.html.erb.tt
@@ -65,10 +69,11 @@ files:
65
69
  - lib/generators/authentication/templates/erb/sessions/sudos/new.html.erb.tt
66
70
  - lib/generators/authentication/templates/mailers/identity_mailer.rb.tt
67
71
  - lib/generators/authentication/templates/mailers/session_mailer.rb.tt
68
- - lib/generators/authentication/templates/migrations/add_omniauth_migration.rb.tt
72
+ - lib/generators/authentication/templates/migrations/create_events_migration.rb.tt
69
73
  - lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt
70
74
  - lib/generators/authentication/templates/migrations/create_table_migration.rb.tt
71
75
  - lib/generators/authentication/templates/models/current.rb.tt
76
+ - lib/generators/authentication/templates/models/event.rb.tt
72
77
  - lib/generators/authentication/templates/models/locking.rb.tt
73
78
  - lib/generators/authentication/templates/models/model.rb.tt
74
79
  - lib/generators/authentication/templates/models/session.rb.tt
@@ -1,8 +0,0 @@
1
- class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
- def change
3
- add_column :<%= table_name %>, :provider, :string
4
- add_column :<%= table_name %>, :uid, :string
5
- end
6
-
7
- add_index :<%= table_name %>, [:provider, :uid], unique: true
8
- end