authkit 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +144 -34
  3. data/Rakefile +8 -0
  4. data/lib/authkit/version.rb +1 -1
  5. data/lib/generators/authkit/install_generator.rb +0 -3
  6. data/lib/generators/authkit/templates/app/controllers/application_controller.rb +20 -13
  7. data/lib/generators/authkit/templates/app/controllers/email_confirmation_controller.rb +21 -3
  8. data/lib/generators/authkit/templates/app/controllers/password_change_controller.rb +37 -5
  9. data/lib/generators/authkit/templates/app/controllers/sessions_controller.rb +3 -1
  10. data/lib/generators/authkit/templates/app/controllers/signup_controller.rb +3 -1
  11. data/lib/generators/authkit/templates/app/models/user.rb +48 -52
  12. data/lib/generators/authkit/templates/app/views/password_change/show.html.erb +1 -0
  13. data/lib/generators/authkit/templates/app/views/sessions/new.html.erb +4 -0
  14. data/lib/generators/authkit/templates/app/views/signup/new.html.erb +5 -1
  15. data/lib/generators/authkit/templates/app/views/users/edit.html.erb +1 -1
  16. data/lib/generators/authkit/templates/spec/controllers/application_controller_spec.rb +26 -26
  17. data/lib/generators/authkit/templates/spec/controllers/email_confirmation_controller_spec.rb +28 -10
  18. data/lib/generators/authkit/templates/spec/controllers/password_change_controller_spec.rb +71 -21
  19. data/lib/generators/authkit/templates/spec/controllers/sessions_controller_spec.rb +14 -0
  20. data/lib/generators/authkit/templates/spec/controllers/signup_controller_spec.rb +14 -0
  21. data/lib/generators/authkit/templates/spec/forms/signup_spec.rb +3 -0
  22. data/lib/generators/authkit/templates/spec/models/user_spec.rb +63 -66
  23. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e32d463ccc3d5bbb3291b087ddb3c51a4341a2c0
4
- data.tar.gz: 16ce8e2e4b53acf18863c454c9def5d1e7a26818
3
+ metadata.gz: 8a50e83ce52b25ebf0d07f9582f6d58485ff4b67
4
+ data.tar.gz: 1f817df72d8bbcde3524b5da618c00ccaa48b8b3
5
5
  SHA512:
6
- metadata.gz: 144e524bb9384e402ef0d0c942e46ce23469858226a354f327cd9ffeaa52b0749a29850a8eb1dac6a4d7d60eb0c7d1e952d958a67e42bb170171961080fe56c3
7
- data.tar.gz: 9f9f94acc22505797557a18fd69ef532aefae1b57cc38f47bf8287f58e6b26a2f08595eaed136296fba001f798cf1f4972b6c921aa89a3adb44b4c0278139a0d
6
+ metadata.gz: 78a53378ab13f476cb291fdc648114a3dc0500f8e92a541e6f8f253e4f35ce0732aafe0de35b953729ec9580f49e957cb793193405512c71fdc1e6f801e794f7
7
+ data.tar.gz: bfa4d0d452bc397d2c8fc5c206182d1bbad95eece55250ad646b53faaf1d26eecf33f6285a41fa28f64178579a8ce879062f35a7093749449bbff165a0bbe1d4
data/README.md CHANGED
@@ -4,21 +4,15 @@ A gem for installing auth into you app.
4
4
 
5
5
  ## Why?
6
6
 
7
- There are lots of great authentication gems out there; devise? clearance? restful_auth?
8
- All of these seek to solve the problem of adding authentication to your application but they all share
9
- one philosophy: you shouldn't need to think about authentication to build your app. For me, I find I
10
- spend way more time trying to figure out how to customize the tools for the few cases when my
11
- application needs to do something different.
7
+ There are lots of great authentication gems out there; devise? clearance? restful_auth? All of these seek to solve the problem of adding authentication to your application but they all share one philosophy: you shouldn't need to think about authentication to build your app. For me, I find I spend way more time trying to figure out how to customize the tools for the few cases when my application needs to do something different.
12
8
 
13
- Authkit takes the opposite stance: auth belongs in your app. It is important and it is specific to your
14
- app. It only includes generators and installs itself with some specs. You customize it. Everything
15
- is right where you would expect it to be.
9
+ Authkit takes the opposite stance: auth belongs in your app. It is important and it is specific to your app. It only includes generators and installs itself with some specs. You customize it. Everything is right where you would expect it to be.
10
+
11
+ Of course, this stance can be very dangerous a it relies on the application developer to not interfere with the authentication mechanisms, and it makes introducing security patches difficult. This is the trade-off. Generally speaking the approaches taken within authkit are designed for the early life-cycle of a small to medium application. It can support much larger platforms, but it is likely that larger platforms will need centralized authentication mechanisms that go beyond the scope of this project.
16
12
 
17
13
  ## Features
18
14
 
19
- Authkit supports Ruby down to version 1.9 but targets 2.0. It is built for Rails 4. It is possible
20
- that it could support Rails 3.x (currently it relies on strong parameters and the Rails 4
21
- message verifier and `secret_key_base`). Some of the features include:
15
+ Authkit supports Ruby down to version 1.9 but targets 2.0. It is built for Rails 4. It is possible that it could support Rails 3.x (currently it relies on strong parameters and the Rails 4 message verifier and `secret_key_base`). Some of the features include:
22
16
 
23
17
  * Signup (username or email)
24
18
  * Login/Logout
@@ -42,8 +36,7 @@ Some possible features include:
42
36
  * Third party accounts
43
37
  * Installer options (test framework, security bulletins, modules)
44
38
 
45
- If there is a feature you don't want to use, you just have to go and delete the generated code.
46
- It is your application to customize.
39
+ If there is a feature you don't want to use, you just have to go and delete the generated code. It is your application to customize.
47
40
 
48
41
  More information is available in [FEATURES](FEATURES.md).
49
42
 
@@ -136,21 +129,150 @@ And will add some gems to your Gemfile:
136
129
  gemfile shoulda-matchers, :test, :development
137
130
  gemfile factor_girl_rails, :test, :development
138
131
 
139
- Once you have this installed you can remove the gem, however you may want to
140
- keep the gem installed in development as you will be able to update it
141
- and check for security bulletins.
132
+ Once you have this installed you can remove the gem, however you may want to keep the gem installed in development as you will be able to update it and check for security bulletins.
142
133
 
143
134
  You'll need to migrate your database (check the migrations before you do):
144
135
 
145
136
  rake db:migrate
146
137
 
147
- You'll also need to connect your mailers for sending password reset instructions
148
- and email confirmations. (See the TODO in `user.rb`)
138
+ You'll also need to connect your mailers for sending password reset instructions and email confirmations. (See the TODO in `user.rb`)
139
+
140
+ ## NOTES
141
+
142
+ Authkit has a number of conventions and requirements that should be noted.
143
+
144
+ * SSL expected
145
+ * secure cookies
146
+ * password complexity is not robust
147
+ * username resrictions are not implemented
148
+ * users do not need to confirm their email address to proceed
149
+ * need a root route
150
+
151
+ ### SSL
152
+
153
+ It is expected that your application be protected by SSL. Though it is possible to segregate your application into SSL/non-SSL areas, Authkit utilizes cookies to store remember token information and assumes that sessions are backed by a cookie store. Because of this you must use SSL to protect against Session Hijacking attacks. Cookies are marked as secure only in the production environment (see `ApplicationController#set_remember_cookie`). If you are using Authkit in a staging environment you might need to adjust this.
154
+
155
+ ### Password and username validation
156
+
157
+ There is only a minimal amount of validation on the password. Because of this users can choose poor passwords (which are not complex or are overly common). To improve this you can adjust the validation in `user.rb`:
158
+
159
+ validates :password, presence: true, confirmation: true, length: {minimum: 6}, if: :password_set?
160
+
161
+ Likewise, there are no restrictions on `username`. If you want to use this field within the URL you will need to constrain the format of the `username` field. Additionally, there may be some user names you want to explicitly disallow based on your routing setup.
162
+
163
+ ### Confirmation not required by default
164
+
165
+ By default, users can begin using the system without confirming their email address. This simplifies the onboarding process, however it means that malicious users may be operating under false pretense. You can change this by adding a check to `ApplicationController#require_login`:
166
+
167
+ def require_login
168
+ deny_user(nil, login_path) unless logged_in?
169
+ deny_user("You need to confirm your email address before proceeding", root_path) unless current_user.email_confirmed?
170
+ end
171
+
172
+ And then in `user.rb`:
173
+
174
+ def email_confirmed?
175
+ self.confirmation_token.blank?
176
+ end
177
+
178
+ ### Root route
179
+
180
+ Additionally, there are several redirects that occur within Authkit (when you have successfully logged in or logged out, etc.). By default the user is redirected to the root_path in these cases. Because of this, you must define a `root` route in your `config/routes.rb`.
181
+
182
+ ## Tokens
183
+
184
+ Authkit makes use of several kinds of tokens:
185
+
186
+ * remember tokens
187
+ * reset password tokens
188
+ * confirmation tokens (email)
189
+ * unlock tokens
190
+ * one time use password tokens
191
+ * api tokens
192
+
193
+ All of the tokens are generated using `SecureRandom.urlsafe_base64(32)`. Each token has a unique index within the database to prevent conflicts but collisions are very unlikely (1/64^32). In the event that a conflict does occur an `ActiveRecord::StatementInvalid` or `ActiveRecord::RecordNotUnique` exeception will be raised.
194
+
195
+ It has been suggested that tokens are essentially passwords (though quite complex ones) and that they should not be stored directly in the database. Instead tokens should be stored using Bcrypt (and stored as a token_digest) to prevent someone with read access from gaining control of an account. This is not currently implemented.
196
+
197
+ Failed attempts are not currently tracked for tokens. Token misses could be used to contribute to `failed_attempts`, however in certain circumstances this could be used to disrupt service by locking accounts. Ideally, invalid tokens would be logged centrally and an existing tool like `fail2ban` could be used to restrict access.
198
+
199
+ You can adjust the default token expiry in `user.rb`.
200
+
201
+ Each of these tokens utilizes a different strategy to protect it from attacks.
202
+
203
+ ### Remember tokens
204
+
205
+ Remember tokens are re-generated every-time a user logs in and the resulting token is stored in a cookie on the user's device (i.e., the browser). The cookie is encrypted, signed and only delivered over secure connections (see SSL above).
206
+
207
+ Because the token is regenerated on every login, any existing remember cookies (for instance, on another device) will be immediately invalidated.
208
+
209
+ Because the cookie mechanism uses `ActiveSupport#MessageVerifier` it is dependent on the security of that class. By default that class securely compares strings and decrypts using strong secret keys (the Rails `secret_key_base` specifically). This protects against timing attacks. Once the verified token is obtained, it can be safely used as part of a database query.
210
+
211
+ Changing your `secret_key_base` will invalidate all existing cookies including all remember cookies. This may be a feature as it is likely that you would want to invalidate all sessions in the event your secret key was compromised.
212
+
213
+ Because the token is not used directly (it must be included in the cookie), even with read access to the database an attacker cannot login without also having the ability to sign the remember cookie.
214
+
215
+ Once the user logs out the token is cleared and is no longer available.
216
+
217
+ ### Reset password tokens
218
+
219
+ When a user forgets their password they can request a password reset so that they can change their password. A new `reset_password_token` is generated when a request is made and an email is sent to the corresponding email address.
220
+
221
+ It is possible to encode the resulting token using the message verifier which could later be used to validate that the token really was generated by the system.
222
+
223
+ Instead the system employs a two-token approach, using both the corresponding email address and the `reset_password_token`. The token is paired with an email parameter so that the user can be found in the database. Once found the tokens can be securely compared to prevent timing attacks. The email address is chosen over the user id because the reset request was generated using the email address and thus is already known. Using the id would increase information leakage.
224
+
225
+ Again, if you are not using SSL this means that the email address and token will be visible in the path information of requests.
226
+
227
+ Once the password is changed, the token is cleared and is no longer available.
228
+
229
+ ### Confirmation tokens
230
+
231
+ When a user signs up or changes their email address an email is sent to the specified address to confirm that the user really controls the email. This is done to ensure that users didn't mistype the address and also protects against malicious users impersonating well known accounts.
232
+
233
+ Like password resets, these tokens are sent directly in email. In the case of email confirmation, however it is possible to require that the user be logged in to utilize the token. Because of this the tokens can easily be compared securely to prevent timing attacks.
234
+
235
+ Once the email is confirmed, the token is cleared and is no longer available.
236
+
237
+ ### Unlock tokens
238
+
239
+ Currently unlock tokens are not implemented. Once implemented unlocks will be sent to logged out users using their email address. Because of this, it is likely that any implementation of unlock tokens will function similar to password reset tokens.
240
+
241
+ ### API tokens
242
+
243
+ Currently API tokens are not implemented. An API token implementation will not have access to a current user. Because of this the API token system can take one of two approaches:
244
+
245
+ 1. Using a `ActiveSupport::MessageVerifier` to generate verified tokens.
246
+ 2. Using a two token approach in the form of `api_access_key` (which is used for database lookups) and `api_secret_token` (which is compared securely).
247
+
248
+ Any implementation of token authentication will likely need to support multiple tokens per account (i.e. a Tokens model). This also allows the user to directly revoke keys.
249
+
250
+ In the case of API access, storing a digest of the token is not practical. Bcrypt digesting is slow and would add a significant amount of overhead if used on every request (on average 90ms with the default 10 stretches).
251
+
252
+ Additionally, storing only the digest means that a user cannot login to see their API tokens. They would need to be regenerated. This might be considered a feature.
253
+
254
+ ## What's missing
255
+
256
+ There is a significant amount of functionality that is currently unimplemented:
257
+
258
+ * Use Bcrypt and token digests instead of storing actual tokens in the database (defense in depth).
259
+ * Full name option (instead of first name and last name)
260
+ * Notification for changes to account (security settings changed)
261
+ * Ability to re-auth for sensitive changes (available for the current session only)
262
+ * API token support
263
+ * OAuth2 client support (but not logging in?) in the form of Facebook support, Twitter support, Google support
264
+ * OAuth2 server support
265
+ * One time password support completed
266
+ * Add Authy or Google Authenticator support
267
+ * Avatars (possibly this should be within uploadkit)
268
+ * User session tracking and revoking
269
+ * Audit logs
270
+ * No internationalization (i18n)
271
+ * JavaScript validation for username and email availability and password complexity
149
272
 
150
273
  ## Testing
151
274
 
152
- The files generated using the installer include specs. To test these you should be
153
- able to:
275
+ The files generated using the installer include specs. To test these you should be able to:
154
276
 
155
277
  $ bundle install
156
278
 
@@ -158,21 +280,9 @@ Then run the default task:
158
280
 
159
281
  $ rake
160
282
 
161
- This will run the specs, which by default will generate a new Rails application,
162
- run the installer, and execute the specs in the context of that temporary
163
- application.
164
-
165
- The specs that are generated utilize a generous amount of mocking and stubbing in
166
- an attempt to keep them fast. However, they use vanilla `rspec-rails`, meaning
167
- they are not using mocha. The two caveats are shoulda-matchers and FactoryGirl which
168
- are required. It is pretty easy to remove these dependencies, it just turned out
169
- that more people were using them than not.
170
-
171
- ## TODO
283
+ This will run the specs, which by default will generate a new Rails application, run the installer, and execute the specs in the context of that temporary application.
172
284
 
173
- * Add oauth2 support (but not logging in?) in the form of facebook support, twitter support, google support
174
- * Add avatar support (maybe that should be uploadkit)
175
- * Add full name option (instead of first name and last name)name
285
+ The specs that are generated utilize a generous amount of mocking and stubbing in an attempt to keep them fast. However, they use vanilla `rspec-rails`, meaning they are not using mocha. The two caveats are shoulda-matchers and FactoryGirl which are required. It is pretty easy to remove these dependencies, it just turned out that more people were using them than not.
176
286
 
177
287
  ## Contributing
178
288
 
data/Rakefile CHANGED
@@ -16,6 +16,11 @@ namespace :spec do
16
16
  end
17
17
  end
18
18
 
19
+ # When using sed to replace in place, don't rely on -i for POSIX compatibility
20
+ def sed(command, filename)
21
+ system "sed '#{command}' #{filename} > #{filename}.tmp && mv #{filename}.tmp #{filename}"
22
+ end
23
+
19
24
  namespace :generator do
20
25
  desc "Cleans up the sample app before running the generator"
21
26
  task :cleanup do
@@ -37,6 +42,9 @@ namespace :generator do
37
42
  system "cd spec/tmp/sample && bundle install"
38
43
  system "cd spec/tmp/sample && rails g rspec:install"
39
44
 
45
+ # Open up the root route for specs
46
+ sed("s/# root/root/", "spec/tmp/sample/config/routes.rb")
47
+
40
48
  # Make a thing
41
49
  system "cd spec/tmp/sample && rails g scaffold thing name:string mood:string"
42
50
  end
@@ -1,3 +1,3 @@
1
1
  module Authkit
2
- VERSION = "0.2.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -70,9 +70,6 @@ module Authkit
70
70
 
71
71
  insert_at_end_of_file "config/initializers/filter_parameter_logging.rb", "config/initializers/filter_parameter_logging.rb"
72
72
 
73
- # Need a temp root
74
- route "root 'welcome#index'"
75
-
76
73
  # Setup the routes
77
74
  route "get '/email/confirm/:token', to: 'email_confirmation#show', as: :confirm"
78
75
 
@@ -4,19 +4,22 @@
4
4
  helper_method :logged_in?, :current_user
5
5
 
6
6
  # It is very unlikely that this exception will be created under normal
7
- # circumstances. Unique validations are handled in Rails, but they are
8
- # also enforced at the database level to guarantee data integrity. In
9
- # certain cases (double-clicking a save link, multiple distributed servers)
10
- # it is possible to get past the Rails validation in which case the
11
- # database throws an exception.
7
+ # circumstances. Unique validations are handled in Rails, but they are also
8
+ # enforced at the database level to guarantee data integrity. In certain
9
+ # cases (double-clicking a save link, multiple distributed servers) it is
10
+ # possible to get past the Rails validation in which case the database throws
11
+ # an exception.
12
12
  rescue_from ActiveRecord::RecordNotUnique, with: :record_not_unique
13
13
 
14
14
  protected
15
15
 
16
+ # The user is fetched using id or remember token but these come from a
17
+ # verified cookie (verified using secure compare) so these database calls do
18
+ # not need to protect against timing attacks.
16
19
  def current_user
17
20
  return @current_user if defined?(@current_user)
18
21
  @current_user ||= User.where(id: session[:user_id]).first if session[:user_id]
19
- @current_user ||= User.user_from_remember_token(cookies.signed[:remember]) unless cookies.signed[:remember].blank?
22
+ set_current_user_from_remember_token unless @current_user
20
23
  session[:user_id] = @current_user.id if @current_user
21
24
  session[:time_zone] = @current_user.time_zone if @current_user
22
25
  set_time_zone
@@ -36,16 +39,12 @@
36
39
  deny_user(nil, login_path) unless logged_in?
37
40
  end
38
41
 
39
- def require_token
40
- deny_user("Invalid token", root_path) unless @user = User.user_from_token(params[:token])
41
- end
42
-
43
- def login(user)
42
+ def login(user, remember=false)
44
43
  reset_session
45
44
  @current_user = user
46
45
  current_user.track_sign_in(request.remote_ip) if allow_tracking?
47
- current_user.set_token(:remember_token)
48
- set_remember_cookie
46
+ current_user.set_remember_token if remember
47
+ set_remember_cookie if remember
49
48
  session[:user_id] = current_user.id
50
49
  session[:time_zone] = current_user.time_zone
51
50
  set_time_zone
@@ -63,6 +62,14 @@
63
62
  Time.zone = session[:time_zone] if session[:time_zone].present?
64
63
  end
65
64
 
65
+ def set_current_user_from_remember_token
66
+ token = cookies.signed[:remember]
67
+ return if token.blank?
68
+ @current_user = User.where(remember_token: token).first
69
+ @current_user = nil if @current_user && @current_user.remember_token_expired?
70
+ @current_user
71
+ end
72
+
66
73
  def set_remember_cookie
67
74
  cookies.permanent.signed[:remember] = {
68
75
  value: current_user.remember_token,
@@ -1,19 +1,21 @@
1
1
  class EmailConfirmationController < ApplicationController
2
+ before_filter :require_login
2
3
  before_filter :require_token
3
4
 
4
5
  respond_to :html
5
6
 
6
7
  def show
7
- if @user.email_confirmed
8
- login(@user)
8
+ if current_user.email_confirmed
9
+ # Do not automatically log in the user
9
10
  flash[:notice] = "Thanks for confirming your email address"
11
+
10
12
  respond_to do |format|
11
13
  format.json { head :no_content }
12
14
  format.html { redirect_to root_path }
13
15
  end
14
16
  else
15
17
  respond_to do |format|
16
- format.json { render json: { status: 'error', errors: @user.errors }.to_json, status: 422 }
18
+ format.json { render json: { status: 'error', errors: current_user.errors }.to_json, status: 422 }
17
19
  format.html {
18
20
  flash[:error] = "Could not confirm email address because it is already in use"
19
21
  redirect_to root_path
@@ -21,5 +23,21 @@ class EmailConfirmationController < ApplicationController
21
23
  end
22
24
  end
23
25
  end
26
+
27
+ protected
28
+
29
+ # Confirmation tokens confirm an email address. It is conceivable
30
+ # that an attacker might choose an address out of their control and attempt to
31
+ # brute-force a confirmation. By default this gains the attacker nothing.
32
+ #
33
+ # It is possible to consider failed confirmation tokens failed attempts and
34
+ # lock the account.
35
+ def require_token
36
+ verifier = ActiveSupport::MessageVerifier.new(Rails.application.config.secret_key_base)
37
+ valid = params[:token].present?
38
+ valid = valid && verifier.send(:secure_compare, params[:token], current_user.confirmation_token)
39
+ valid = valid && !current_user.confirmation_token_expired?
40
+ deny_user("Invalid token", root_path) unless valid
41
+ end
24
42
  end
25
43
 
@@ -1,4 +1,6 @@
1
1
  class PasswordChangeController < ApplicationController
2
+ before_filter :require_no_user
3
+ before_filter :require_email_user
2
4
  before_filter :require_token
3
5
 
4
6
  def show
@@ -9,21 +11,51 @@ class PasswordChangeController < ApplicationController
9
11
  end
10
12
 
11
13
  def create
12
- if @user.change_password(params[:password], params[:password_confirmation])
13
- login(@user)
14
-
14
+ if email_user.change_password(params[:password], params[:password_confirmation])
15
+ # Do not automatically log in the user
15
16
  respond_to do |format|
16
17
  format.json { head :no_content }
17
18
  format.html {
18
19
  flash.now[:notice] = "Password updated successfully"
19
- redirect_to(root_path)
20
+ redirect_to(login_path)
20
21
  }
21
22
  end
22
23
  else
23
24
  respond_to do |format|
24
- format.json { render json: { status: 'error', errors: @user.errors }.to_json, status: 422 }
25
+ format.json { render json: { status: 'error', errors: email_user.errors }.to_json, status: 422 }
25
26
  format.html { render :show }
26
27
  end
27
28
  end
28
29
  end
30
+
31
+ protected
32
+
33
+ # Any existing user should be logged out to prevent session leakage
34
+ def require_no_user
35
+ logout
36
+ end
37
+
38
+ # The token is paired with an email parameter so that the user can be
39
+ # found in the database. Once found the tokens can be securely compared
40
+ # to prevent timing attacks. The email address is chosen over the id
41
+ # because the reset was generated using the email address and thus is
42
+ # already known. Using the id would increase information leakage.
43
+ def require_email_user
44
+ deny_user("Invalid email address", root_path) if params[:email].blank? || email_user.blank?
45
+ end
46
+
47
+ def email_user
48
+ return @user if defined?(@user)
49
+ @user = User.where(email: params[:email]).first || raise(ActiveRecord::RecordNotFound)
50
+ end
51
+
52
+ # Reset password tokens expire after 1 day
53
+ def require_token
54
+ verifier = ActiveSupport::MessageVerifier.new(Rails.application.config.secret_key_base)
55
+ valid = params[:token].present?
56
+ valid = valid && verifier.send(:secure_compare, params[:token], email_user.reset_password_token)
57
+ valid = valid && !email_user.reset_password_token_expired?
58
+ deny_user("Invalid token", root_path) unless valid
59
+ end
60
+
29
61
  end
@@ -4,8 +4,10 @@ class SessionsController < ApplicationController
4
4
  end
5
5
 
6
6
  def create
7
+ remember = params[:remember_me] == "1"
8
+
7
9
  if user && user.authenticate(params[:password])
8
- login(user)
10
+ login(user, remember)
9
11
  respond_to do |format|
10
12
  format.json { head :no_content }
11
13
  format.html { redirect_back_or_default }