authentication-zero 2.16.11 → 2.16.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c322e94333e2ab7cb4267e120c023f0de6bc908b5f91f966dc315ebe24fa99a
4
- data.tar.gz: a472b502f2f0795d457aa7afa5c678fbe368c5cb98399c200416fee0caaa8573
3
+ metadata.gz: fd4aba188e6a8763ada4f0cc90f370e8980afd0903e3e5f17a5f4bcc5db7c8d6
4
+ data.tar.gz: 8e16e20f5ed9d2cf1aadd469bdeffae20e1c51ab030bb5731697ae37dd749079
5
5
  SHA512:
6
- metadata.gz: 76a33fb738dfdeba9ab24a4189dabae296a1c3a369f96b771a202481f3361d576412998ffce4f97a193d47c51bb693d22028f0e33f4ff44b85be9f1c5ee151b3
7
- data.tar.gz: ee103521ed7fe35a8afaa3a6cd8c669a3b999c20bbb783fe0f889daec2391e6820bc44a4e0113754b8b0297e4e68345fbc1f8c1450e2676460706ddb0e412af2
6
+ metadata.gz: dc0688a6b1fae46b456d7c7ce473f1a4414f13bf9bc29439c6d687a67e9122d58eb76e592ef2796c79f1b0e19816e66e6a92f7278dc9df31c9595382108016ce
7
+ data.tar.gz: 06d51e04679f0821a4cb296f2e06f588c0614b75ae1f8ca6ce370cbca494d950280b617e8f6346539ddbe8d412838c9fdb9fceb4b6315d47b3471e30b9b7cd19
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## Authentication Zero 2.16.13 ##
2
+
3
+ * Enable resend invitation
4
+ * Refactor first_or_initialize -> find_or_initialize_by
5
+
6
+ ## Authentication Zero 2.16.12 ##
7
+
8
+ * Bring back --sudoable, just for html and you should set before_action yourself
9
+ * Bring back --ratelimit
10
+ * Removed signed in email notification
11
+
1
12
  ## Authentication Zero 2.16.11 ##
2
13
 
3
14
  * Added sending invitation
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authentication-zero (2.16.11)
4
+ authentication-zero (2.16.13)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -33,11 +33,12 @@ Since Authentication Zero generates this code into your application instead of b
33
33
  - Send invitations (--invitable)
34
34
  - Verify email using a link with token
35
35
  - Verify email using a six random digits code for api (--code-verifiable)
36
+ - Ask password before sensitive data changes, aka: sudo (--sudoable)
36
37
  - Reset the user password and send reset instructions
37
38
  - Reset the user password only from verified emails
38
- - Lock mechanism for resetting password (--lockable)
39
+ - Lock mechanism to prevent spamming (--lockable)
40
+ - Rate limiting for your app, 1000 reqs/minute (--ratelimit)
39
41
  - Send e-mail confirmation when your email has been changed
40
- - Send e-mail notification when someone has logged into your account
41
42
  - Manage multiple sessions & devices
42
43
  - Activity log (--trackable)
43
44
  - Log out
@@ -53,6 +54,7 @@ Since Authentication Zero generates this code into your application instead of b
53
54
  - [log filtering](https://guides.rubyonrails.org/action_controller_overview.html#log-filtering): Parameters 'token' and 'password' are marked [FILTERED] in the log.
54
55
  - [functional tests](https://guides.rubyonrails.org/testing.html#functional-tests-for-your-controllers): In Rails, testing the various actions of a controller is a form of writing functional tests.
55
56
  - [system testing](https://guides.rubyonrails.org/testing.html#system-testing): System tests allow you to test user interactions with your application, running tests in either a real or a headless browser.
57
+ - **sudoable**: Use `before_action :require_sudo` in controllers with sensitive information, it will ask for your password on the first access or after 30 minutes.
56
58
 
57
59
  ## Development
58
60
 
@@ -1,3 +1,3 @@
1
1
  module AuthenticationZero
2
- VERSION = "2.16.11"
2
+ VERSION = "2.16.13"
3
3
  end
@@ -6,7 +6,9 @@ class AuthenticationGenerator < Rails::Generators::Base
6
6
  class_option :api, type: :boolean, desc: "Generates API authentication"
7
7
  class_option :pwned, type: :boolean, desc: "Add pwned password validation"
8
8
  class_option :code_verifiable, type: :boolean, desc: "Add email verification using a code for api"
9
+ class_option :sudoable, type: :boolean, desc: "Add password request before sensitive data changes"
9
10
  class_option :lockable, type: :boolean, desc: "Add password reset locking"
11
+ class_option :ratelimit, type: :boolean, desc: "Add request rate limiting"
10
12
  class_option :passwordless, type: :boolean, desc: "Add passwordless sign"
11
13
  class_option :omniauthable, type: :boolean, desc: "Add social login support"
12
14
  class_option :trackable, type: :boolean, desc: "Add activity log support"
@@ -18,6 +20,10 @@ class AuthenticationGenerator < Rails::Generators::Base
18
20
  def add_gems
19
21
  gem "bcrypt", "~> 3.1.7", comment: "Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]"
20
22
 
23
+ if options.ratelimit?
24
+ gem "rack-ratelimit", group: :production, comment: "Use Rack::Ratelimit to rate limit requests [https://github.com/jeremy/rack-ratelimit]"
25
+ end
26
+
21
27
  if redis?
22
28
  gem "redis", ">= 4.0.1", comment: "Use Redis adapter to run additional authentication features"
23
29
  gem "kredis", comment: "Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]"
@@ -41,6 +47,7 @@ class AuthenticationGenerator < Rails::Generators::Base
41
47
  def add_environment_configurations
42
48
  application "config.action_mailer.default_url_options = { host: \"localhost\", port: 3000 }", env: "development"
43
49
  application "config.action_mailer.default_url_options = { host: \"localhost\", port: 3000 }", env: "test"
50
+ environment ratelimit_block, env: "production" if options.ratelimit?
44
51
  end
45
52
 
46
53
  def create_configuration_files
@@ -81,6 +88,7 @@ class AuthenticationGenerator < Rails::Generators::Base
81
88
  template "controllers/#{format_folder}/invitations_controller.rb", "app/controllers/invitations_controller.rb" if invitable?
82
89
  template "controllers/#{format_folder}/registrations_controller.rb", "app/controllers/registrations_controller.rb"
83
90
  template "controllers/#{format_folder}/home_controller.rb", "app/controllers/home_controller.rb" unless options.api?
91
+ template "controllers/#{format_folder}/sessions/sudos_controller.rb", "app/controllers/sessions/sudos_controller.rb" if sudoable?
84
92
  template "controllers/#{format_folder}/sessions/omniauth_controller.rb", "app/controllers/sessions/omniauth_controller.rb" if omniauthable?
85
93
  template "controllers/#{format_folder}/sessions/passwordlesses_controller.rb", "app/controllers/sessions/passwordlesses_controller.rb" if passwordless?
86
94
  template "controllers/#{format_folder}/authentications/events_controller.rb", "app/controllers/authentications/events_controller.rb" if options.trackable?
@@ -89,10 +97,8 @@ class AuthenticationGenerator < Rails::Generators::Base
89
97
  def create_views
90
98
  if options.api?
91
99
  directory "erb/user_mailer", "app/views/user_mailer"
92
- directory "erb/session_mailer", "app/views/session_mailer"
93
100
  else
94
101
  directory "erb/user_mailer", "app/views/user_mailer"
95
- directory "erb/session_mailer", "app/views/session_mailer"
96
102
 
97
103
  directory "erb/home", "app/views/home"
98
104
 
@@ -105,6 +111,8 @@ class AuthenticationGenerator < Rails::Generators::Base
105
111
  template "erb/sessions/index.html.erb", "app/views/sessions/index.html.erb"
106
112
  template "erb/sessions/new.html.erb", "app/views/sessions/new.html.erb"
107
113
 
114
+ directory "erb/sessions/sudos", "app/views/sessions/sudos" if sudoable?
115
+
108
116
  directory "erb/sessions/passwordlesses", "app/views/sessions/passwordlesses" if passwordless?
109
117
 
110
118
  directory "erb/two_factor_authentication", "app/views/two_factor_authentication" if two_factor?
@@ -119,6 +127,10 @@ class AuthenticationGenerator < Rails::Generators::Base
119
127
  def add_routes
120
128
  route "root 'home#index'" unless options.api?
121
129
 
130
+ if sudoable?
131
+ route "resource :sudo, only: [:new, :create]", namespace: :sessions
132
+ end
133
+
122
134
  if passwordless?
123
135
  route "resource :passwordless, only: [:new, :edit, :create]", namespace: :sessions
124
136
  end
@@ -163,6 +175,13 @@ class AuthenticationGenerator < Rails::Generators::Base
163
175
  options.api? ? "api" : "html"
164
176
  end
165
177
 
178
+ def ratelimit_block
179
+ <<~CODE
180
+ # Rate limit general requests by IP address in a rate of 1000 requests per minute
181
+ config.middleware.use(Rack::Ratelimit, name: "General", rate: [1000, 1.minute], redis: Redis.new, logger: Rails.logger) { |env| ActionDispatch::Request.new(env).ip }
182
+ CODE
183
+ end
184
+
166
185
  def omniauthable?
167
186
  options.omniauthable? && !options.api?
168
187
  end
@@ -179,11 +198,15 @@ class AuthenticationGenerator < Rails::Generators::Base
179
198
  options.invitable? && !options.api?
180
199
  end
181
200
 
201
+ def sudoable?
202
+ options.sudoable? && !options.api?
203
+ end
204
+
182
205
  def code_verifiable?
183
206
  options.code_verifiable? && options.api?
184
207
  end
185
208
 
186
209
  def redis?
187
- options.lockable? || code_verifiable?
210
+ options.lockable? || options.ratelimit? || sudoable? || code_verifiable?
188
211
  end
189
212
  end
@@ -1,9 +1,6 @@
1
1
  class SessionsController < ApplicationController
2
2
  skip_before_action :authenticate, only: :create
3
3
 
4
- <%- if options.lockable? -%>
5
- before_action :require_lock, attempts: 20, only: :create
6
- <%- end -%>
7
4
  before_action :set_session, only: %i[ show destroy ]
8
5
 
9
6
  def index
@@ -1,6 +1,12 @@
1
1
  class ApplicationController < ActionController::Base
2
2
  before_action :set_current_request_details
3
3
  before_action :authenticate
4
+ <%- if sudoable? %>
5
+ def require_sudo
6
+ return if Current.session.sudo?
7
+ redirect_to new_sessions_sudo_path(proceed_to_url: request.url)
8
+ end
9
+ <%- end -%>
4
10
  <%- if options.lockable? %>
5
11
  def require_lock(wait: 1.hour, attempts: 10)
6
12
  counter = Kredis.counter("require_lock:#{request.remote_ip}:#{controller_path}:#{action_name}", expires_in: wait)
@@ -4,7 +4,7 @@ class InvitationsController < ApplicationController
4
4
  end
5
5
 
6
6
  def create
7
- @user = User.new(user_params)
7
+ @user = User.create_with(user_params).find_or_initialize_by(email: params[:email])
8
8
 
9
9
  if @user.save
10
10
  send_invitation_instructions
@@ -3,7 +3,7 @@ class Sessions::OmniauthController < ApplicationController
3
3
  skip_before_action :authenticate
4
4
 
5
5
  def create
6
- @user = User.where(omniauth_params).first_or_initialize(user_params)
6
+ @user = User.create_with(user_params).find_or_initialize_by(omniauth_params)
7
7
 
8
8
  if @user.save
9
9
  session = @user.sessions.create!
@@ -20,14 +20,14 @@ class Sessions::OmniauthController < ApplicationController
20
20
  end
21
21
 
22
22
  private
23
- def omniauth_params
24
- { provider: omniauth.provider, uid: omniauth.uid }
25
- end
26
-
27
23
  def user_params
28
24
  { email: omniauth.info.email, password: SecureRandom::base58, verified: true }
29
25
  end
30
26
 
27
+ def omniauth_params
28
+ { provider: omniauth.provider, uid: omniauth.uid }
29
+ end
30
+
31
31
  def omniauth
32
32
  request.env["omniauth.auth"]
33
33
  end
@@ -0,0 +1,14 @@
1
+ class Sessions::SudosController < ApplicationController
2
+ def new
3
+ end
4
+
5
+ def create
6
+ session = Current.session
7
+
8
+ if session.user.authenticate(params[:password])
9
+ session.sudo.mark; redirect_to(params[:proceed_to_url])
10
+ else
11
+ redirect_to new_sessions_sudo_path(proceed_to_url: params[:proceed_to_url]), alert: "The password you entered is incorrect"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ <p style="color: red"><%%= alert %></p>
2
+
3
+ <h1>Enter your password to continue</h1>
4
+
5
+ <%%= form_with(url: sessions_sudo_path) do |form| %>
6
+
7
+ <%%= form.hidden_field :proceed_to_url, value: params[:proceed_to_url] %>
8
+
9
+ <div>
10
+ <%%= form.password_field :password, required: true, autofocus: true, autocomplete: "current-password" %>
11
+ </div>
12
+
13
+ <div>
14
+ <%%= form.submit "Continue" %>
15
+ </div>
16
+ <%% end %>
17
+
18
+ <br>
19
+
20
+ <p>
21
+ <strong>Why are you asking me to do this?</strong><br>
22
+ To better protect your account, we'll occasionally ask you to confirm your password before performing sensitive actions.
23
+ </p>
24
+
25
+ <p>
26
+ <strong>Forgot your password?</strong><br>
27
+ We'll help you <%%= link_to "reset it", new_identity_password_reset_path %> so you can continue.
28
+ </p>
@@ -1,21 +1,18 @@
1
1
  class Session < ApplicationRecord
2
2
  belongs_to :user
3
+ <%- if sudoable? %>
4
+ kredis_flag :sudo, expires_in: 30.minutes
5
+ <%- end -%>
3
6
 
4
7
  before_create do
5
8
  self.user_agent = Current.user_agent
6
9
  self.ip_address = Current.ip_address
7
10
  end
8
-
9
- after_create_commit do
10
- SessionMailer.with(session: self).signed_in_notification.deliver_later
11
- end
11
+ <%- if sudoable? %>
12
+ after_create { sudo.mark }
13
+ <%- end -%>
12
14
  <%- if options.trackable? %>
13
- after_create do
14
- user.events.create! action: "signed_in"
15
- end
16
-
17
- after_destroy do
18
- user.events.create! action: "signed_out"
19
- end
15
+ after_create { user.events.create! action: "signed_in" }
16
+ after_destroy { user.events.create! action: "signed_out" }
20
17
  <%- end -%>
21
18
  end
@@ -21,8 +21,6 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
21
21
 
22
22
  test "should sign in" do
23
23
  post sign_in_url, params: { email: @user.email, password: "Secret1*3*5*" }
24
-
25
- assert_enqueued_email_with SessionMailer, :signed_in_notification, args: { session: @user.sessions.last }
26
24
  assert_response :created
27
25
  end
28
26
 
@@ -19,8 +19,6 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
19
19
 
20
20
  test "should sign in" do
21
21
  post sign_in_url, params: { email: @user.email, password: "Secret1*3*5*" }
22
- assert_enqueued_email_with SessionMailer, :signed_in_notification, args: { session: @user.sessions.last }
23
-
24
22
  assert_redirected_to root_url
25
23
 
26
24
  get root_url
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.16.11
4
+ version: 2.16.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nixon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-02 00:00:00.000000000 Z
11
+ date: 2023-04-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -56,6 +56,7 @@ files:
56
56
  - lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt
57
57
  - lib/generators/authentication/templates/controllers/html/sessions/omniauth_controller.rb.tt
58
58
  - lib/generators/authentication/templates/controllers/html/sessions/passwordlesses_controller.rb.tt
59
+ - lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
59
60
  - lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt
60
61
  - lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenges_controller.rb.tt
61
62
  - lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt
@@ -67,17 +68,16 @@ files:
67
68
  - lib/generators/authentication/templates/erb/invitations/new.html.erb.tt
68
69
  - lib/generators/authentication/templates/erb/passwords/edit.html.erb.tt
69
70
  - lib/generators/authentication/templates/erb/registrations/new.html.erb.tt
70
- - lib/generators/authentication/templates/erb/session_mailer/signed_in_notification.html.erb.tt
71
71
  - lib/generators/authentication/templates/erb/sessions/index.html.erb.tt
72
72
  - lib/generators/authentication/templates/erb/sessions/new.html.erb.tt
73
73
  - lib/generators/authentication/templates/erb/sessions/passwordlesses/new.html.erb.tt
74
+ - lib/generators/authentication/templates/erb/sessions/sudos/new.html.erb.tt
74
75
  - lib/generators/authentication/templates/erb/two_factor_authentication/challenges/new.html.erb.tt
75
76
  - lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt
76
77
  - lib/generators/authentication/templates/erb/user_mailer/email_verification.html.erb.tt
77
78
  - lib/generators/authentication/templates/erb/user_mailer/invitation_instructions.html.erb.tt
78
79
  - lib/generators/authentication/templates/erb/user_mailer/password_reset.html.erb.tt
79
80
  - lib/generators/authentication/templates/erb/user_mailer/passwordless.html.erb.tt
80
- - lib/generators/authentication/templates/mailers/session_mailer.rb.tt
81
81
  - lib/generators/authentication/templates/mailers/user_mailer.rb.tt
82
82
  - lib/generators/authentication/templates/migrations/create_email_verification_tokens_migration.rb.tt
83
83
  - lib/generators/authentication/templates/migrations/create_events_migration.rb.tt
@@ -105,7 +105,6 @@ files:
105
105
  - lib/generators/authentication/templates/test_unit/controllers/html/passwords_controller_test.rb.tt
106
106
  - lib/generators/authentication/templates/test_unit/controllers/html/registrations_controller_test.rb.tt
107
107
  - lib/generators/authentication/templates/test_unit/controllers/html/sessions_controller_test.rb.tt
108
- - lib/generators/authentication/templates/test_unit/mailers/session_mailer_test.rb.tt
109
108
  - lib/generators/authentication/templates/test_unit/mailers/user_mailer_test.rb.tt
110
109
  - lib/generators/authentication/templates/test_unit/system/identity/emails_test.rb.tt
111
110
  - lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt
@@ -1,21 +0,0 @@
1
- <p>Hey there,</p>
2
-
3
- <p>A new device just signed in to your account (<%%= @session.user.email %>).</p>
4
-
5
- <p>
6
- <strong><%%= @session.user_agent %></strong>
7
- <br>
8
- <%%= @session.created_at %>
9
- <br>
10
- IP address: <%%= @session.ip_address %>
11
- </p>
12
-
13
- <p><strong>If this was you, carry on.</strong> We could notify you about sign-ins from this device again.</p>
14
-
15
- <p><strong>If you don't recognize this device</strong>, someone else may have accessed your account. You should immediately <%%= link_to "change your password", new_identity_password_reset_url %>.</p>
16
-
17
- <p><strong>Tip:</strong> It's a good idea to periodically review all of the <%%= link_to "devices and sessions", sessions_url %> in your account for suspicious activity.</p>
18
-
19
- <hr>
20
-
21
- <p>Have questions or need help? Just reply to this email and our support team will help you sort it out.</p>
@@ -1,6 +0,0 @@
1
- class SessionMailer < ApplicationMailer
2
- def signed_in_notification
3
- @session = params[:session]
4
- mail to: @session.user.email, subject: "New sign-in to your account"
5
- end
6
- end
@@ -1,13 +0,0 @@
1
- require "test_helper"
2
-
3
- class SessionMailerTest < ActionMailer::TestCase
4
- setup do
5
- @session = users(:lazaro_nixon).sessions.create!
6
- end
7
-
8
- test "signed_in_notification" do
9
- mail = SessionMailer.with(session: @session).signed_in_notification
10
- assert_equal "New sign-in to your account", mail.subject
11
- assert_equal [@session.user.email], mail.to
12
- end
13
- end