authentication-zero 0.0.14 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
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 +5 -5
  6. data/lib/generators/authentication/templates/controllers/api/emails_controller.rb.tt +0 -4
  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 -4
  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: 0f9beaffb78e2f198c9276df8dda0a72f8029b55cd7d5b282aeb5c30b9abe02e
4
- data.tar.gz: 2f7fb5ced42bde9126bae2a876ce58127e0b1ad27f4b6fbf8b675656ea557873
3
+ metadata.gz: 5f48325c2122dac114a46a7949ba07ab7693872f198076dc7bcfae87b31441c1
4
+ data.tar.gz: 4117615d796766e17a773707f2dba9616eaf1ca7a59c007c831431d9b09e18eb
5
5
  SHA512:
6
- metadata.gz: 3a6602f790b8e9da67546b711df55b9e6e196d22bf06b12dfa8a2c84359d1d21d77a22a28d8eec4c06208ff2d27090c93e2c034e1d5e859370552886d518ffe6
7
- data.tar.gz: 9535c89a33b6b0f8bfc50a8b5039a989b68e3204fdbca48f2501ba13d84cab77a9ef737329f0adf874a1f1b53694c0452aafe1ef5278f93df59198cf28286bf9
6
+ metadata.gz: a6c76a600c3a82bb51bdb638bc1d114aef80ed13b2a252af3fac6bd4e1cd05992004a9bb6ec33457cb56e0fa93a3f48209acfb5d9c41c1ca7f9542104166e01b
7
+ data.tar.gz: 277192f60768925670f1580c13a0f593e27f92656987171818e09edff379b7571b88abcf0460ae9961477557bfe186e7b1a4e05e46c1ff24f760e2d0ff959301
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authentication-zero (0.0.14)
4
+ authentication-zero (0.0.18)
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.14"
2
+ VERSION = "0.0.18"
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,8 +59,8 @@ 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) }
63
- Current.user = #{singular_table_name}
62
+ if #{singular_table_name} = authenticate_with_http_token { |t, _| #{class_name}.find_signed_session_token(t) }
63
+ Current.#{singular_table_name} = #{singular_table_name}
64
64
  else
65
65
  request_http_token_authentication
66
66
  end
@@ -73,8 +73,8 @@ 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])
77
- Current.user = #{singular_table_name}
76
+ if #{singular_table_name} = #{class_name}.find_by_session_token(cookies.signed[:session_token])
77
+ Current.#{singular_table_name} = #{singular_table_name}
78
78
  else
79
79
  redirect_to sign_in_path, alert: "You need to sign in or sign up before continuing"
80
80
  end
@@ -5,10 +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
-
12
8
  render json: @<%= singular_table_name %>
13
9
  else
14
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,10 +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
-
15
11
  redirect_to root_path, notice: "Your email has been changed successfully"
16
12
  else
17
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.14
4
+ version: 0.0.18
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: