authentication-zero 0.0.13 → 0.0.17

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 (21) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +25 -0
  4. data/lib/authentication_zero/version.rb +1 -1
  5. data/lib/generators/authentication/authentication_generator.rb +3 -3
  6. data/lib/generators/authentication/templates/controllers/api/emails_controller.rb.tt +0 -3
  7. data/lib/generators/authentication/templates/controllers/api/password_resets_controller.rb.tt +1 -2
  8. data/lib/generators/authentication/templates/controllers/api/passwords_controller.rb.tt +0 -1
  9. data/lib/generators/authentication/templates/controllers/api/sessions_controller.rb.tt +2 -2
  10. data/lib/generators/authentication/templates/controllers/html/emails_controller.rb.tt +0 -3
  11. data/lib/generators/authentication/templates/controllers/html/password_resets_controller.rb.tt +2 -3
  12. data/lib/generators/authentication/templates/controllers/html/passwords_controller.rb.tt +0 -1
  13. data/lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt +1 -1
  14. data/lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt +2 -2
  15. data/lib/generators/authentication/templates/mailers/email_mailer.rb.tt +1 -1
  16. data/lib/generators/authentication/templates/models/resource.rb.tt +25 -4
  17. data/lib/generators/authentication/templates/views/password_mailer/reset.html.erb.tt +1 -1
  18. data/lib/generators/authentication/templates/views/password_mailer/reset.text.erb.tt +1 -1
  19. data/lib/generators/authentication/templates/views/password_resets/edit.html.erb.tt +1 -1
  20. data/lib/generators/authentication/templates/views/password_resets/new.html.erb.tt +1 -1
  21. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e853cd032072f4c6dc76b99cdff704b392eac57abea2893957b03f93c7069bd
4
- data.tar.gz: 49428b1a84e2cd03beba0f9f5a39623f06c33ae20072a691130885391b09d615
3
+ metadata.gz: efb4d895a3678027d6ead3a365d35a5cd7d5b7fc87c7ffe69140b9f4d9fcd705
4
+ data.tar.gz: 8757ea47c7e1a86abac000c42689e6e05c987609037a66254308135c4662dc77
5
5
  SHA512:
6
- metadata.gz: aa5510a1671afde349053941f76876b888b481fbae4839dd7724b38163c3ca37c8a68ad73f2eb1de277f80bfbc3ad9d4e21f5d07613a24f09bc78d9e7b051bec
7
- data.tar.gz: 1578a6bc1502f0d1f0f25b6b993f4f1be297f367532ce604f1da5926de5bd9fb38bbcc36705b98c2a8fd3cca933bd2649b81cdc9007fbf4dfcb63065758835a0
6
+ metadata.gz: e68ee610e427b081e6e462a86651382e556a674242f66154a51727b2c396f907417509a80aa4aaf343433ddf8f02bfb30af099f75b49657232fc47282930a964
7
+ data.tar.gz: 43afeb2c6e2b0444c5b7970839b698934e37c85befb1b35b60eac0d43128cb22b63a2d18e1fc3d64796628ddebc27e6e879989e11bda9d56a84cbc584439d373
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authentication-zero (0.0.13)
4
+ authentication-zero (0.0.17)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  The purpose of authentication zero is to generate a pre-built authentication system into a rails application (web or api-only) that follows both security and rails best practices. By generating code into the user's application instead of using a library, the user has complete freedom to modify the authentication system so it works best with their app.
4
4
 
5
+ ## Features
6
+
7
+ - Sign up
8
+ - Email and password validations
9
+ - Reset the user password and send reset instructions
10
+ - Authentication by cookie (html)
11
+ - Authentication by token (api)
12
+ - Remember me (html)
13
+ - Send e-mail when email is changed
14
+ - Send e-mail when password is changed
15
+ - Cancel my account
16
+ - Log out
17
+
18
+ ## Security and best practices
19
+
20
+ - [Current attributes](https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html): Abstract super class that provides a thread-isolated attributes singleton, which resets automatically before and after each request.
21
+ - [has_secure_password](https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password): Adds methods to set and authenticate against a BCrypt password.
22
+ - [has_secure_token](https://api.rubyonrails.org/classes/ActiveRecord/SecureToken/ClassMethods.html#method-i-has_secure_token): Adds methods to generate unique tokens.
23
+ - [signed_id](https://api.rubyonrails.org/classes/ActiveRecord/SignedId.html): Returns a signed id that is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
24
+ - [Signed cookies](https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html): Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from the cookie again.
25
+ - [Http only cookies](https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html): A cookie with the httponly attribute is inaccessible to the JavaScript, this precaution helps mitigate cross-site scripting (XSS) attacks.
26
+ - [Log filtering](https://guides.rubyonrails.org/action_controller_overview.html#log-filtering): Parameters 'token' and 'password' are marked [FILTERED] in the log.
27
+ - [Callbacks](https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html): We use callbacks to send emails after changing an email or password.
28
+ - [Action mailer](https://api.rubyonrails.org/classes/ActionMailer/Base.html): Action Mailer allows you to send email from your application using a mailer model and views.
29
+
5
30
  ## Installation
6
31
 
7
32
  Add this lines to your application's Gemfile:
@@ -1,3 +1,3 @@
1
1
  module AuthenticationZero
2
- VERSION = "0.0.13"
2
+ VERSION = "0.0.17"
3
3
  end
@@ -16,7 +16,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
16
16
  end
17
17
 
18
18
  def create_mailers
19
- template "mailers/email_mailer.rb", "app/mailers/email_mailer.rb"
19
+ template "mailers/email_mailer.rb", "app/mailers/email_mailer.rb"
20
20
  template "mailers/password_mailer.rb", "app/mailers/password_mailer.rb"
21
21
  end
22
22
 
@@ -59,7 +59,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
59
59
 
60
60
  private
61
61
  def authenticate
62
- if #{singular_table_name} = authenticate_with_http_token { |token, _| #{class_name}.find_by_session_token(token) }
62
+ if #{singular_table_name} = authenticate_with_http_token { |t, _| #{class_name}.find_signed_session_token(t) }
63
63
  Current.user = #{singular_table_name}
64
64
  else
65
65
  request_http_token_authentication
@@ -73,7 +73,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
73
73
 
74
74
  private
75
75
  def authenticate
76
- if #{singular_table_name} = cookies[:session_token] && #{class_name}.find_by_session_token(cookies[:session_token])
76
+ if #{singular_table_name} = #{class_name}.find_by_session_token(cookies.signed[:session_token])
77
77
  Current.user = #{singular_table_name}
78
78
  else
79
79
  redirect_to sign_in_path, alert: "You need to sign in or sign up before continuing"
@@ -5,9 +5,6 @@ class EmailsController < ApplicationController
5
5
  if !@<%= singular_table_name %>.authenticate(params[:current_password])
6
6
  render json: { error: "The current password you entered is incorrect" }, status: :bad_request
7
7
  elsif @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
8
- if @<%= singular_table_name %>.email_previously_changed?
9
- EmailMailer.with(email_change: @<%= singular_table_name %>.email_previous_change).changed.deliver_later
10
- end
11
8
  render json: @<%= singular_table_name %>
12
9
  else
13
10
  render json: @<%= singular_table_name %>.errors, status: :unprocessable_entity
@@ -1,6 +1,5 @@
1
1
  class PasswordResetsController < ApplicationController
2
2
  skip_before_action :authenticate
3
-
4
3
  before_action :set_<%= singular_table_name %>, only: %i[ edit update ]
5
4
 
6
5
  def edit
@@ -25,7 +24,7 @@ class PasswordResetsController < ApplicationController
25
24
 
26
25
  private
27
26
  def set_<%= singular_table_name %>
28
- @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:sid], purpose: "password_reset")
27
+ @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:token], purpose: "password_reset")
29
28
  rescue ActiveSupport::MessageVerifier::InvalidSignature
30
29
  render json: { error: "Your token has expired, please request a new one" }, status: :bad_request
31
30
  end
@@ -5,7 +5,6 @@ class PasswordsController < ApplicationController
5
5
  if !@<%= singular_table_name %>.authenticate(params[:current_password])
6
6
  render json: { error: "The current password you entered is incorrect" }, status: :bad_request
7
7
  elsif @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
8
- PasswordMailer.with(user: @<%= singular_table_name %>).changed.deliver_later
9
8
  render json: @<%= singular_table_name %>
10
9
  else
11
10
  render json: @<%= singular_table_name %>.errors, status: :unprocessable_entity
@@ -5,9 +5,9 @@ class SessionsController < ApplicationController
5
5
  @<%= singular_table_name %> = <%= class_name %>.find_by_email(params[:email])
6
6
 
7
7
  if @<%= singular_table_name %>.try(:authenticate, params[:password])
8
- render json: { session_token: @<%= singular_table_name %>.session_token }
8
+ render json: { session_token: @<%= singular_table_name %>.signed_session_token }
9
9
  else
10
- render json: { error: "Invalid session token" }, status: :unauthorized
10
+ render json: { error: "Invalid email or password" }, status: :unauthorized
11
11
  end
12
12
  end
13
13
 
@@ -8,9 +8,6 @@ class EmailsController < ApplicationController
8
8
  if !@<%= singular_table_name %>.authenticate(params[:current_password])
9
9
  redirect_to edit_emails_path, alert: "The current password you entered is incorrect"
10
10
  elsif @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
11
- if @<%= singular_table_name %>.email_previously_changed?
12
- EmailMailer.with(email_change: @<%= singular_table_name %>.email_previous_change).changed.deliver_later
13
- end
14
11
  redirect_to root_path, notice: "Your email has been changed successfully"
15
12
  else
16
13
  render :edit, status: :unprocessable_entity
@@ -1,6 +1,5 @@
1
1
  class PasswordResetsController < ApplicationController
2
2
  skip_before_action :authenticate
3
-
4
3
  before_action :set_<%= singular_table_name %>, only: %i[ edit update ]
5
4
 
6
5
  def new
@@ -14,7 +13,7 @@ class PasswordResetsController < ApplicationController
14
13
  PasswordMailer.with(<%= singular_table_name %>: @<%= singular_table_name %>).reset.deliver_later
15
14
  redirect_to sign_in_path, notice: "You will receive an email with instructions on how to reset your password in a few minutes"
16
15
  else
17
- redirect_to new_password_resets_path, alert: "The email address doesn't exist in our database"
16
+ redirect_to new_password_resets_path(email_hint: params[:email]), alert: "The email address doesn't exist in our database"
18
17
  end
19
18
  end
20
19
 
@@ -28,7 +27,7 @@ class PasswordResetsController < ApplicationController
28
27
 
29
28
  private
30
29
  def set_<%= singular_table_name %>
31
- @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:sid], purpose: "password_reset")
30
+ @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:token], purpose: "password_reset")
32
31
  rescue ActiveSupport::MessageVerifier::InvalidSignature
33
32
  redirect_to new_password_resets_path, alert: "Your token has expired, please request a new one"
34
33
  end
@@ -8,7 +8,6 @@ class PasswordsController < ApplicationController
8
8
  if !@<%= singular_table_name %>.authenticate(params[:current_password])
9
9
  redirect_to edit_passwords_path, alert: "The current password you entered is incorrect"
10
10
  elsif @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
11
- PasswordMailer.with(user: @<%= singular_table_name %>).changed.deliver_later
12
11
  redirect_to root_path, notice: "Your password has been changed successfully"
13
12
  else
14
13
  render :edit, status: :unprocessable_entity
@@ -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
- cookies[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
12
+ cookies.signed[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
13
13
  redirect_to root_path, notice: "Welcome! You have signed up successfully"
14
14
  else
15
15
  render :new, status: :unprocessable_entity
@@ -10,9 +10,9 @@ class SessionsController < ApplicationController
10
10
 
11
11
  if @<%= singular_table_name %>.try(:authenticate, params[:password])
12
12
  if params[:remember_me] == "1"
13
- cookies.permanent[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
13
+ cookies.signed.permanent[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
14
14
  else
15
- cookies[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
15
+ cookies.signed[:session_token] = { value: @<%= singular_table_name %>.session_token, httponly: true }
16
16
  end
17
17
 
18
18
  redirect_to root_path, notice: "Signed in successfully"
@@ -1,6 +1,6 @@
1
1
  class EmailMailer < ApplicationMailer
2
2
  def changed
3
- @previous_email, @current_email = params[:email_change]
3
+ @previous_email, @current_email = params[:change]
4
4
  mail to: @previous_email
5
5
  end
6
6
  end
@@ -6,9 +6,30 @@ class <%= class_name %> < ApplicationRecord
6
6
  validates :email, format: { with: /\A[^@\s]+@[^@\s]+\z/ }
7
7
  validates_length_of :password, minimum: 8, allow_blank: true
8
8
 
9
- before_validation { self.email = email.downcase.strip }
9
+ before_validation do
10
+ self.email = email.downcase.strip
11
+ end
10
12
 
11
- def as_json(options)
12
- super(options.merge(except: [:password_digest, :session_token]))
13
- end
13
+ after_update_commit do
14
+ if self.email_previously_changed?
15
+ EmailMailer.with(change: self.email_previous_change).changed.deliver_later
16
+ end
17
+ end
18
+
19
+ after_update_commit do
20
+ if self.password_digest_previously_changed?
21
+ PasswordMailer.with(<%= singular_table_name %>: self).changed.deliver_later
22
+ end
23
+ end
24
+ <% if options.api? %>
25
+ def signed_session_token
26
+ self.class.signed_id_verifier.generate(session_token)
27
+ end
28
+
29
+ def self.find_signed_session_token(signed_session_token)
30
+ if session_token = signed_id_verifier.verified(signed_session_token)
31
+ find_by_session_token(session_token)
32
+ end
33
+ end
34
+ <% end -%>
14
35
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  <p>Can't remember your password for <strong><%%= params[:<%= singular_table_name %>].email %></strong>? That's OK, it happens. Just hit the link below to set a new one.</p>
4
4
 
5
- <p><%%= link_to "Reset my password", edit_password_resets_url(sid: @signed_id) %></p>
5
+ <p><%%= link_to "Reset my password", edit_password_resets_url(token: @signed_id) %></p>
6
6
 
7
7
  <p>If you did not request a password reset you can safely ignore this email, it expires in 20 minutes. Only someone with access to this email account can reset your password.</p>
8
8
 
@@ -2,7 +2,7 @@ Hey there,
2
2
 
3
3
  Can't remember your password for <%%= params[:<%= singular_table_name %>].email %>? That's OK, it happens. Just hit the link below to set a new one.
4
4
 
5
- [Reset my password]<%%= edit_password_resets_url(sid: @signed_id) %>
5
+ [Reset my password]<%%= edit_password_resets_url(token: @signed_id) %>
6
6
 
7
7
  If you did not request a password reset you can safely ignore this email, it expires in 20 minutes. Only someone with access to this email account can reset your password.
8
8
 
@@ -13,7 +13,7 @@
13
13
  </div>
14
14
  <%% end %>
15
15
 
16
- <%%= hidden_field_tag :sid, params[:sid] %>
16
+ <%%= hidden_field_tag :token, params[:token] %>
17
17
 
18
18
  <div>
19
19
  <%%= form.label :password, "New password", style: "display: block" %>
@@ -5,7 +5,7 @@
5
5
  <%%= form_with(url: password_resets_path) do |form| %>
6
6
  <div>
7
7
  <%%= form.label :email, style: "display: block" %>
8
- <%%= form.email_field :email, autofocus: true, required: true %>
8
+ <%%= form.email_field :email, value: params[:email_hint], autofocus: true, required: true %>
9
9
  </div>
10
10
 
11
11
  <div>
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: 0.0.13
4
+ version: 0.0.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nixon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-17 00:00:00.000000000 Z
11
+ date: 2022-02-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: