authenticate 0.1.0 → 0.2.0

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +0 -4
  4. data/Gemfile.lock +0 -5
  5. data/README.md +149 -78
  6. data/app/controllers/authenticate/passwords_controller.rb +130 -0
  7. data/app/controllers/authenticate/sessions_controller.rb +46 -0
  8. data/app/controllers/authenticate/users_controller.rb +46 -0
  9. data/app/mailers/authenticate_mailer.rb +13 -0
  10. data/app/views/authenticate_mailer/change_password.html.erb +8 -0
  11. data/app/views/authenticate_mailer/change_password.text.erb +5 -0
  12. data/app/views/layouts/application.html.erb +25 -0
  13. data/app/views/passwords/edit.html.erb +20 -0
  14. data/app/views/passwords/new.html.erb +19 -0
  15. data/app/views/sessions/new.html.erb +28 -0
  16. data/app/views/users/new.html.erb +24 -0
  17. data/authenticate.gemspec +1 -2
  18. data/config/locales/authenticate.en.yml +57 -0
  19. data/config/routes.rb +14 -1
  20. data/lib/authenticate/callbacks/brute_force.rb +5 -9
  21. data/lib/authenticate/callbacks/lifetimed.rb +1 -0
  22. data/lib/authenticate/callbacks/timeoutable.rb +2 -1
  23. data/lib/authenticate/callbacks/trackable.rb +1 -3
  24. data/lib/authenticate/configuration.rb +94 -5
  25. data/lib/authenticate/controller.rb +69 -9
  26. data/lib/authenticate/debug.rb +1 -0
  27. data/lib/authenticate/engine.rb +4 -11
  28. data/lib/authenticate/model/brute_force.rb +22 -3
  29. data/lib/authenticate/model/db_password.rb +12 -7
  30. data/lib/authenticate/model/email.rb +8 -10
  31. data/lib/authenticate/model/password_reset.rb +76 -0
  32. data/lib/authenticate/model/timeoutable.rb +9 -3
  33. data/lib/authenticate/model/trackable.rb +1 -1
  34. data/lib/authenticate/model/username.rb +21 -8
  35. data/lib/authenticate/modules.rb +19 -1
  36. data/lib/authenticate/session.rb +3 -1
  37. data/lib/authenticate/user.rb +6 -1
  38. data/lib/authenticate/version.rb +1 -1
  39. data/lib/generators/authenticate/controllers/USAGE +12 -0
  40. data/lib/generators/authenticate/controllers/controllers_generator.rb +21 -0
  41. data/lib/generators/authenticate/install/USAGE +7 -0
  42. data/lib/generators/authenticate/install/install_generator.rb +140 -0
  43. data/lib/generators/authenticate/install/templates/authenticate.rb +22 -0
  44. data/lib/generators/authenticate/install/templates/db/migrate/add_authenticate_brute_force_to_users.rb +6 -0
  45. data/lib/generators/authenticate/install/templates/db/migrate/add_authenticate_password_reset_to_users.rb +7 -0
  46. data/lib/generators/authenticate/install/templates/db/migrate/add_authenticate_timeoutable_to_users.rb +5 -0
  47. data/lib/generators/authenticate/install/templates/db/migrate/add_authenticate_to_users.rb +21 -0
  48. data/lib/generators/authenticate/install/templates/db/migrate/create_users.rb +14 -0
  49. data/lib/generators/authenticate/install/templates/user.rb +3 -0
  50. data/lib/generators/authenticate/routes/USAGE +8 -0
  51. data/lib/generators/authenticate/routes/routes_generator.rb +32 -0
  52. data/lib/generators/authenticate/routes/templates/routes.rb +10 -0
  53. data/lib/generators/authenticate/views/USAGE +13 -0
  54. data/lib/generators/authenticate/views/views_generator.rb +21 -0
  55. data/spec/dummy/app/controllers/application_controller.rb +1 -0
  56. data/spec/dummy/config/initializers/authenticate.rb +12 -5
  57. data/spec/dummy/db/development.sqlite3 +0 -0
  58. data/spec/dummy/db/migrate/20160130192728_create_users.rb +18 -0
  59. data/spec/dummy/db/migrate/20160130192729_add_authenticate_brute_force_to_users.rb +6 -0
  60. data/spec/dummy/db/migrate/20160130192730_add_authenticate_timeoutable_to_users.rb +5 -0
  61. data/spec/dummy/db/migrate/20160130192731_add_authenticate_password_reset_to_users.rb +7 -0
  62. data/spec/dummy/db/schema.rb +14 -10
  63. data/spec/dummy/db/test.sqlite3 +0 -0
  64. data/spec/factories/users.rb +5 -8
  65. data/spec/model/brute_force_spec.rb +63 -0
  66. data/spec/model/session_spec.rb +4 -0
  67. data/spec/model/user_spec.rb +15 -5
  68. data/spec/spec_helper.rb +2 -1
  69. metadata +41 -9
  70. data/app/controllers/.keep +0 -0
  71. data/app/mailers/.keep +0 -0
  72. data/app/views/.keep +0 -0
  73. data/spec/dummy/db/migrate/20160120003910_create_users.rb +0 -18
@@ -100,7 +100,9 @@ module Authenticate
100
100
 
101
101
  def write_cookie
102
102
  cookie_hash = {
103
- httponly: true,
103
+ path: Authenticate.configuration.cookie_path,
104
+ secure: Authenticate.configuration.secure_cookie,
105
+ httponly: Authenticate.configuration.cookie_http_only,
104
106
  value: @current_user.session_token,
105
107
  expires: Authenticate.configuration.cookie_expiration.call
106
108
  }
@@ -35,16 +35,21 @@ module Authenticate
35
35
  load_modules
36
36
  end
37
37
 
38
+ # Generate a new session token for the user, overwriting the existing session token, if any.
39
+ # This is not automatically persisted; call {#reset_session_token!} to automatically
40
+ # generate and persist the session token update.
38
41
  def generate_session_token
39
42
  self.session_token = Authenticate::Token.new
40
- # puts 'User.generate_session_token session_token:' + self.session_token.to_s
41
43
  end
42
44
 
45
+ # Generate a new session token and persist the change, ignoring validations.
46
+ # This effectively signs out all existing sessions. Called as part of logout.
43
47
  def reset_session_token!
44
48
  generate_session_token
45
49
  save validate: false
46
50
  end
47
51
 
52
+
48
53
  end
49
54
  end
50
55
 
@@ -1,3 +1,3 @@
1
1
  module Authenticate
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,12 @@
1
+ Description:
2
+ Override the default authentication controllers and mailers. This generator will copy all of the
3
+ base authenticate controllers and mailers into your project.
4
+
5
+ Examples:
6
+ rails generate authenticate:controllers
7
+
8
+ View: app/controllers/authenticate/passwords_controller.rb
9
+ View: app/controllers/authenticate/sessions_controller.rb
10
+ View: app/controllers/authenticate/users_controller.rb
11
+ View: app/mailers/authenticate_mailer.rb
12
+
@@ -0,0 +1,21 @@
1
+ require 'rails/generators/base'
2
+
3
+ #
4
+ # deploy view and locale assets
5
+ #
6
+ module Authenticate
7
+ module Generators
8
+ class ControllersGenerator < Rails::Generators::Base
9
+ source_root File.expand_path("../../../../..", __FILE__)
10
+
11
+ def create_views
12
+ directory 'app/controllers'
13
+ end
14
+
15
+ def create_mailers
16
+ directory 'app/mailers'
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate authenticate:install
6
+
7
+ This will create:
@@ -0,0 +1,140 @@
1
+ require 'rails/generators/base'
2
+ require 'rails/generators/active_record'
3
+
4
+ module Authenticate
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ def create_initializer
11
+ copy_file 'authenticate.rb', 'config/initializers/authenticate.rb'
12
+ end
13
+
14
+ def inject_into_application_controller
15
+ inject_into_class(
16
+ "app/controllers/application_controller.rb",
17
+ ApplicationController,
18
+ " include Authenticate::Controller\n"
19
+ )
20
+ end
21
+
22
+ def create_or_inject_into_user_model
23
+ if File.exist? "app/models/user.rb"
24
+ inject_into_file(
25
+ 'app/models/user.rb',
26
+ ' include Authenticate::User\n\n',
27
+ after: 'class User < ActiveRecord::Base\n'
28
+ )
29
+ else
30
+ copy_file 'user.rb', 'app/models/user.rb'
31
+ end
32
+ end
33
+
34
+ def create_authenticate_user_migration
35
+ if users_table_exists?
36
+ create_add_columns_migration
37
+ else
38
+ create_new_users_migration
39
+ end
40
+ end
41
+
42
+ def copy_migration_files
43
+ copy_migration 'add_authenticate_brute_force_to_users.rb'
44
+ copy_migration 'add_authenticate_timeoutable_to_users.rb'
45
+ copy_migration 'add_authenticate_password_reset_to_users.rb'
46
+ end
47
+
48
+ private
49
+
50
+ def create_new_users_migration
51
+ config = {
52
+ new_columns: new_columns,
53
+ new_indexes: new_indexes
54
+ }
55
+ copy_migration 'create_users.rb', config
56
+ end
57
+
58
+ def create_add_columns_migration
59
+ if migration_needed?
60
+ config = {
61
+ new_columns: new_columns,
62
+ new_indexes: new_indexes
63
+ }
64
+ copy_migration('add_authenticate_to_users.rb', config)
65
+ end
66
+ end
67
+
68
+ def copy_migration(migration_name, config = {})
69
+ unless migration_exists?(migration_name)
70
+ migration_template(
71
+ "db/migrate/#{migration_name}",
72
+ "db/migrate/#{migration_name}",
73
+ config
74
+ )
75
+ end
76
+ end
77
+
78
+ def migration_needed?
79
+ new_columns.any? || new_indexes.any?
80
+ end
81
+
82
+ def new_columns
83
+ @new_columns ||= {
84
+ email: 't.string :email',
85
+ encrypted_password: 't.string :encrypted_password, limit: 128',
86
+ session_token: 't.string :session_token, limit: 128',
87
+
88
+ # trackable, lifetimed
89
+ current_sign_in_at: 't.datetime :current_sign_in_at',
90
+ current_sign_in_ip: 't.string :current_sign_in_ip, limit: 128',
91
+ last_sign_in_at: 't.datetime :last_sign_in_at',
92
+ last_sign_in_ip: 't.string :last_sign_in_ip, limit: 128',
93
+ sign_in_count: 't.integer :sign_in_count'
94
+ }.reject { |column| existing_users_columns.include?(column.to_s) }
95
+ end
96
+
97
+ def new_indexes
98
+ @new_indexes ||= {
99
+ index_users_on_email: 'add_index :users, :email',
100
+ index_users_on_session_token: 'add_index :users, :session_token'
101
+ }.reject { |index| existing_users_indexes.include?(index.to_s) }
102
+ end
103
+
104
+ def migration_exists?(name)
105
+ existing_migrations.include?(name)
106
+ end
107
+
108
+ def existing_migrations
109
+ @existing_migrations ||= Dir.glob("db/migrate/*.rb").map do |file|
110
+ migration_name_without_timestamp(file)
111
+ end
112
+ end
113
+
114
+ def migration_name_without_timestamp(file)
115
+ file.sub(%r{^.*(db/migrate/)(?:\d+_)?}, '')
116
+ end
117
+
118
+ def users_table_exists?
119
+ ActiveRecord::Base.connection.table_exists?(:users)
120
+ end
121
+
122
+ def existing_users_columns
123
+ return [] unless users_table_exists?
124
+ ActiveRecord::Base.connection.columns(:users).map(&:name)
125
+ end
126
+
127
+ def existing_users_indexes
128
+ return [] unless users_table_exists?
129
+ ActiveRecord::Base.connection.indexes(:users).map(&:name)
130
+ end
131
+
132
+ # for generating a timestamp when using `create_migration`
133
+ def self.next_migration_number(dir)
134
+ ActiveRecord::Generators::Base.next_migration_number(dir)
135
+ end
136
+
137
+
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,22 @@
1
+ Authenticate.configure do |config|
2
+ # config.user_model = 'User'
3
+ # config.cookie_name = 'authenticate_session_token'
4
+ # config.cookie_expiration = { 1.month.from_now.utc }
5
+ # config.cookie_domain = nil
6
+ # config.cookie_path = '/'
7
+ # config.secure_cookie = false # set to true in production https environments
8
+ # config.cookie_http_only = false # set to true if you can
9
+
10
+ # config.mailer_sender = 'reply@example.com'
11
+ # config.crypto_provider = Authenticate::Model::BCrypt
12
+ # config.timeout_in = 45.minutes
13
+ # config.max_session_lifetime = 8.hours
14
+ # config.max_consecutive_bad_logins_allowed = 4
15
+ # config.bad_login_lockout_period = 10.minutes
16
+ # config.authentication_strategy = :email
17
+ # config.redirect_url = '/'
18
+ # config.allow_sign_up = true
19
+ # config.routes = true
20
+ # config.reset_password_within = 2.days
21
+ # config.modules = []
22
+ end
@@ -0,0 +1,6 @@
1
+ class AddAuthenticateBruteForceToUsers < ActiveRecord::Migration
2
+ def change
3
+ add_column :users, :failed_logins_count, :integer, default: 0
4
+ add_column :users, :lock_expires_at, :datetime, default: nil
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ class AddAuthenticatePasswordResetToUsers < ActiveRecord::Migration
2
+ def change
3
+ add_column :users, :password_reset_token, :string, default: nil
4
+ add_column :users, :password_reset_sent_at, :datetime, default: nil
5
+ end
6
+ end
7
+
@@ -0,0 +1,5 @@
1
+ class AddAuthenticateTimeoutableToUsers < ActiveRecord::Migration
2
+ def change
3
+ add_column :users, :last_access_at, :datetime, default: nil
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ class AddAuthenticateToUsers < ActiveRecord::Migration
2
+ def self.up
3
+ change_table :users do |t|
4
+ <% config[:new_columns].values.each do |column| -%>
5
+ <%= column %>
6
+ <% end -%>
7
+ end
8
+
9
+ <% config[:new_indexes].values.each do |index| -%>
10
+ <%= index %>
11
+ <% end -%>
12
+ end
13
+
14
+ def self.down
15
+ change_table :users do |t|
16
+ <% if config[:new_columns].any? -%>
17
+ t.remove <%= new_columns.keys.map { |column| ":#{column}" }.join(", ") %>
18
+ <% end -%>
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+
4
+ create_table :users do |t|
5
+ <% config[:new_columns].values.each do |column| -%>
6
+ <%= column %>
7
+ <% end -%>
8
+ end
9
+
10
+ <% config[:new_indexes].values.each do |index| -%>
11
+ <%= index %>
12
+ <% end -%>
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ include Authenticate::User
3
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Inject the authenticate routes into your `config/routes.rb`. Also turns off authenticate's built-in routes
3
+ by adding `config.routes = false` into your `config/initializers/authenticate.rb`.
4
+
5
+ Examples:
6
+ rails generate authenticate:routes
7
+
8
+
@@ -0,0 +1,32 @@
1
+ require 'rails/generators/base'
2
+
3
+ module Authenticate
4
+ module Generators
5
+ class RoutesGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ def add_authenticate_routes
9
+ route(authenticate_routes)
10
+ end
11
+
12
+ def disable_authenticate_internal_routes
13
+ inject_into_file(
14
+ 'config/initializers/authenticate.rb',
15
+ " config.routes = false \n",
16
+ after: "Authenticate.configure do |config|\n",
17
+ )
18
+ end
19
+
20
+ private
21
+
22
+ def authenticate_routes
23
+ File.read(routes_file_path)
24
+ end
25
+
26
+ def routes_file_path
27
+ File.expand_path(find_in_source_paths('routes.rb'))
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ resource :session, controller: 'authenticate/sessions', only: [:create, :new, :destroy]
2
+ resources :passwords, controller: 'authenticate/passwords', only: [:new, :create]
3
+
4
+ resource :users, controller: 'authenticate/users', only: [:new, :create] do
5
+ resources :passwords, controller: 'authenticate/passwords', only: [:edit, :update]
6
+ end
7
+
8
+ get '/sign_up', to: 'authenticate/users#new', as: 'sign_up'
9
+ get '/sign_in', to: 'authenticate/sessions#new', as: 'sign_in'
10
+ get '/sign_out', to: 'authenticate/sessions#destroy', as: 'sign_out'
@@ -0,0 +1,13 @@
1
+ Description:
2
+ Override the default authenticate views. This generator will copy all of the
3
+ base authenticate views into your project.
4
+
5
+ Examples:
6
+ rails generate authenticate:views
7
+
8
+ View: app/views/authenticate_mailer/change_password.html.erb
9
+ View: app/views/layouts/application.html.erb
10
+ View: app/views/passwords/edit.html.erb
11
+ View: app/views/passwords/new.html.erb
12
+ View: app/views/sessions/new.html.erb
13
+ View: app/views/users/new.html.erb
@@ -0,0 +1,21 @@
1
+ require 'rails/generators/base'
2
+
3
+ #
4
+ # deploy view and locale assets
5
+ #
6
+ module Authenticate
7
+ module Generators
8
+ class ViewsGenerator < Rails::Generators::Base
9
+ source_root File.expand_path("../../../../..", __FILE__)
10
+
11
+ def create_views
12
+ directory 'app/views'
13
+ end
14
+
15
+ def create_locales
16
+ directory 'config/locales'
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,5 @@
1
1
  class ApplicationController < ActionController::Base
2
+ include Authenticate::Controller
2
3
  # Prevent CSRF attacks by raising an exception.
3
4
  # For APIs, you may want to use :null_session instead.
4
5
  protect_from_forgery with: :exception
@@ -1,7 +1,14 @@
1
- puts '************************** initializer start'
2
1
  Authenticate.configure do |config|
3
- config.debug = true
4
- config.timeout_in = 5.minutes
5
- config.max_session_lifetime = 10.minutes
2
+ # config.user_model = 'User'
3
+ # config.cookie_name = 'authenticate_session_token'
4
+ # config.cookie_expiration = { 1.month.from_now.utc }
5
+ # config.cookie_domain = nil
6
+ # config.cookie_path = '/'
7
+ # config.secure_cookie = false # set to true in production https environments
8
+ # config.http_only = false # set to true if you can
9
+ # config.timeout_in = 45.minutes
10
+ # config.max_session_lifetime = 8.hours
11
+ config.max_consecutive_bad_logins_allowed = 1
12
+ config.bad_login_lockout_period = 2.minutes
13
+ # config.authentication_strategy = :email
6
14
  end
7
- puts '************************** initializer finished'
Binary file