authenticate 0.1.0 → 0.2.0

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