authentication-zero 2.8.3 → 2.9.1

Sign up to get free protection for your applications and to get access to all the features.
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