devise_token_auth 0.1.28.beta6 → 0.1.28.beta7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +75 -20
  3. data/app/controllers/devise_token_auth/application_controller.rb +12 -0
  4. data/app/controllers/devise_token_auth/auth_controller.rb +1 -2
  5. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +26 -10
  6. data/app/controllers/devise_token_auth/confirmations_controller.rb +1 -3
  7. data/app/controllers/devise_token_auth/passwords_controller.rb +11 -15
  8. data/app/controllers/devise_token_auth/registrations_controller.rb +16 -14
  9. data/app/controllers/devise_token_auth/sessions_controller.rb +2 -6
  10. data/app/models/devise_token_auth/concerns/user.rb +49 -1
  11. data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
  12. data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
  13. data/config/initializers/devise.rb +9 -0
  14. data/lib/devise_token_auth.rb +2 -0
  15. data/lib/devise_token_auth/controllers/helpers.rb +129 -0
  16. data/lib/devise_token_auth/controllers/url_helpers.rb +8 -0
  17. data/lib/devise_token_auth/engine.rb +4 -0
  18. data/lib/devise_token_auth/version.rb +1 -1
  19. data/test/controllers/demo_group_controller_test.rb +126 -0
  20. data/test/controllers/{demo_controller_test.rb → demo_mang_controller_test.rb} +32 -59
  21. data/test/controllers/demo_user_controller_test.rb +262 -0
  22. data/test/controllers/devise_token_auth/auth_controller_test.rb +1 -1
  23. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +19 -6
  24. data/test/controllers/devise_token_auth/passwords_controller_test.rb +35 -7
  25. data/test/controllers/devise_token_auth/registrations_controller_test.rb +61 -8
  26. data/test/dummy/app/controllers/demo_group_controller.rb +13 -0
  27. data/test/dummy/app/controllers/demo_mang_controller.rb +12 -0
  28. data/test/dummy/app/controllers/demo_user_controller.rb +12 -0
  29. data/test/dummy/config/routes.rb +6 -5
  30. data/test/dummy/db/development.sqlite3 +0 -0
  31. data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +5 -0
  32. data/test/dummy/db/schema.rb +2 -3
  33. data/test/dummy/db/test.sqlite3 +0 -0
  34. data/test/dummy/log/development.log +3977 -0
  35. data/test/dummy/log/test.log +165539 -0
  36. data/test/dummy/tmp/generators/app/controllers/application_controller.rb +8 -0
  37. data/test/dummy/tmp/generators/app/models/user.rb +0 -4
  38. data/test/dummy/tmp/generators/db/migrate/{20140916215707_devise_token_auth_create_users.rb → 20140922164332_devise_token_auth_create_users.rb} +0 -0
  39. data/test/lib/generators/devise_token_auth/install_generator_test.rb +2 -2
  40. data/test/models/user_test.rb +0 -12
  41. data/test/test_helper.rb +9 -9
  42. metadata +22 -8
  43. data/test/dummy/app/controllers/demo_controller.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ccede2e6459d83a37149b44ca415539e272f8281
4
- data.tar.gz: 42832f0c9d06fec5a801692fef0295894990ca7d
3
+ metadata.gz: 10be5a0682b4707bdc008fb2962bee2e00b79ad9
4
+ data.tar.gz: 72f1c4e5ef9007b9a547cc8473ffe1f6bf0b227d
5
5
  SHA512:
6
- metadata.gz: 17fd41de34801ae46b9065f8bff43c3195f7f8d8383eb04a187bbae210f5cedf1a296cadbb0c49ef66bb5a87c498258e0314d86e106d42acdd6b300ff84d365e
7
- data.tar.gz: 9919f37387990dcd43525a6bdd8436245195c18e51c0deebd60d0e1418370240f70bc9df222f7bd771174d9d0e56da401361306db35553f15175761992fd4437
6
+ metadata.gz: ca0fcd9e0b3ce18849b28aae0536ca97ba5652f0ba5612e0cb28ab2fba4cc208b7a01db1c2d581898af0e395453349da6732b98523237465d980a38208514784
7
+ data.tar.gz: 0f2fe4f15ae311eb5d31aeb89805650f3f2114d045a085b8f1ee69040f20f4436f90eb72cb0d326ab42f5dc0e489f86c3d00a7a2caf8a465e4cc26b1c96af18e
data/README.md CHANGED
@@ -288,48 +288,67 @@ The authentication routes must be mounted to your project. This gem includes a r
288
288
  mount_devise_token_auth_for 'User', at: '/auth'
289
289
  ~~~
290
290
 
291
- Any model class can be used, but the class will need to include [`DeviseTokenAuth::Concerns::SetUserByToken`](#model-concerns) for authentication to work properly.
291
+ Any model class can be used, but the class will need to include [`DeviseTokenAuth::Concerns::User`](#model-concerns) for authentication to work properly.
292
292
 
293
293
  You can mount this engine to any route that you like. `/auth` is used by default to conform with the defaults of the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module.
294
294
 
295
295
 
296
- ## Controller Concerns
296
+ ## Controller Methods
297
297
 
298
- ##### DeviseTokenAuth::Concerns::SetUserByToken
298
+ ### Concerns
299
299
 
300
- This gem includes a [Rails concern](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html) called `DeviseTokenAuth::Concerns::SetUserByToken`. This concern can be used in controllers to identify users by their authentication headers.
301
-
302
- This concern runs a [before_action](http://guides.rubyonrails.org/action_controller_overview.html#filters), setting the `@user` variable for use in your controllers. The user will be signed in via devise for the duration of the request.
300
+ This gem includes a [Rails concern](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html) called `DeviseTokenAuth::Concerns::SetUserByToken`. Include this concern to provide access to [controller methods](#controller-methods) such as [`authenticate_user!`](#authenticate-user), [`user_signed_in?`](#user-signed-in), etc.
303
301
 
304
302
  The concern also runs an [after_action](http://guides.rubyonrails.org/action_controller_overview.html#filters) that changes the auth token after each request.
305
303
 
306
304
  It is recommended to include the concern in your base `ApplicationController` so that all children of that controller include the concern as well.
307
305
 
306
+ ##### Concern example:
307
+
308
308
  ~~~ruby
309
309
  # app/controllers/application_controller.rb
310
310
  class ApplicationController < ActionController::Base
311
311
  include DeviseTokenAuth::Concerns::SetUserByToken
312
312
  end
313
+ ~~~
314
+
315
+ ### Methods
316
+
317
+ This gem provides access to all of the following [devise helpers](https://github.com/plataformatec/devise#controller-filters-and-helpers):
318
+
319
+ | Method | Description |
320
+ |---|---|
321
+ | **`before_action :authenticate_user!`** | Returns a 401 error unless a `User` is signed-in. |
322
+ | **`current_user`** | Returns the currently signed-in `User`, or `nil` if unavailable. |
323
+ | **`user_signed_in?`** | Returns `true` if a `User` is signed in, otherwise `false`. |
324
+ | **`devise_token_auth_group`** | Operate on multiple user classes as a group. [Read more](#group-access) |
313
325
 
326
+ Note that if the model that you're trying to access isn't called `User`, the helper method names will change. For example, if the user model is called `Admin`, the methods would look like this:
327
+
328
+ * `before_action :authenticate_admin!`
329
+ * `admin_signed_in?`
330
+ * `current_admin`
331
+
332
+
333
+ ##### Example: limit access to authenticated users
334
+ ~~~ruby
314
335
  # app/controllers/test_controller.rb
315
336
  class TestController < ApplicationController
337
+ before_action :authenticate_user!
338
+
316
339
  def members_only
317
- if @user
318
- render json: {
319
- data: {
320
- message: "Welcome #{@user.name}",
321
- user: @user
322
- }
323
- }, status: 200
324
- else
325
- render json: {
326
- errors: ["Authorized users only."]
327
- }, status: 401
328
- end
340
+ render json: {
341
+ data: {
342
+ message: "Welcome #{current_user.name}",
343
+ user: current_user
344
+ }
345
+ }, status: 200
329
346
  end
330
347
  end
331
348
  ~~~
332
349
 
350
+ ### Token Header Format
351
+
333
352
  The authentication information should be included by the client in the headers of each request. The headers follow the [RFC 6750 Bearer Token](http://tools.ietf.org/html/rfc6750) format:
334
353
 
335
354
  ##### Authentication headers example:
@@ -354,11 +373,11 @@ The authentication headers required for each request will be available in the re
354
373
 
355
374
  ## Model Concerns
356
375
 
357
- ##### DeviseTokenAuth::Concerns::SetUserByToken
376
+ ##### DeviseTokenAuth::Concerns::User
358
377
 
359
378
  Typical use of this gem will not require the use of any of the following model methods. All authentication should be handled invisibly by the [controller concerns](#controller-concerns) described above.
360
379
 
361
- Models that include the `DeviseTokenAuth::Concerns::SetUserByToken` concern will have access to the following public methods (read the above section for context on `token` and `client`):
380
+ Models that include the `DeviseTokenAuth::Concerns::User` concern will have access to the following public methods (read the above section for context on `token` and `client`):
362
381
 
363
382
  * **`valid_token?`**: check if an authentication token is valid. Accepts a `token` and `client` as arguments. Returns a boolean.
364
383
 
@@ -408,6 +427,8 @@ Models that include the `DeviseTokenAuth::Concerns::SetUserByToken` concern will
408
427
 
409
428
  ## Using multiple models
410
429
 
430
+ ### [View Live Multi-User Demo](http://ng-token-auth-demo.herokuapp.com/multi-user)
431
+
411
432
  This gem supports the use of multiple user models. One possible use case is to authenticate visitors using a model called `User`, and to authenticate administrators with a model called `Admin`. Take the following steps to add another authentication model to your app:
412
433
 
413
434
  1. Run the install generator for the new model.
@@ -442,6 +463,40 @@ This gem supports the use of multiple user models. One possible use case is to a
442
463
  end
443
464
  end
444
465
  ~~~
466
+
467
+ 1. Configure any `Admin` restricted controllers. Controllers will now have access to the methods [described here](#methods):
468
+ * `before_action: :authenticate_admin!`
469
+ * `current_admin`
470
+ * `admin_signed_in?`
471
+
472
+
473
+ ### Group access
474
+
475
+ It is also possible to control access to multiple user types at the same time using groups. The following example shows how to limit controller access to both `User` and `Admin` users.
476
+
477
+ ##### Example: group authentication
478
+
479
+ ~~~ruby
480
+ class DemoGroupController < ApplicationController
481
+ devise_token_auth_group :member, contains: [:user, :admin]
482
+ before_action :authenticate_member!
483
+
484
+ def members_only
485
+ render json: {
486
+ data: {
487
+ message: "Welcome #{current_member.name}",
488
+ user: current_member
489
+ }
490
+ }, status: 200
491
+ end
492
+ end
493
+ ~~~
494
+
495
+ In the above example, the following methods will be available (in addition to `current_user`, `current_admin`, etc.):
496
+
497
+ * `before_action: :authenticate_member!`
498
+ * `current_member`
499
+ * `member_signed_in?`
445
500
 
446
501
  # Conceptual
447
502
 
@@ -1,5 +1,17 @@
1
1
  module DeviseTokenAuth
2
2
  class ApplicationController < DeviseController
3
3
  include DeviseTokenAuth::Concerns::SetUserByToken
4
+ respond_to :json
5
+
6
+
7
+ def resource_class(m=nil)
8
+ if m
9
+ mapping = Devise.mappings[m]
10
+ else
11
+ mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
12
+ end
13
+
14
+ mapping.to
15
+ end
4
16
  end
5
17
  end
@@ -1,8 +1,8 @@
1
1
  module DeviseTokenAuth
2
2
  class AuthController < DeviseTokenAuth::ApplicationController
3
- respond_to :json
4
3
  skip_after_filter :update_auth_header, :only => [:omniauth_success, :omniauth_failure]
5
4
  skip_before_filter :assert_is_devise_resource!, :only => [:validate_token]
5
+ before_filter :set_user_by_token, :only => [:validate_token]
6
6
 
7
7
  def validate_token
8
8
  # @user will have been set by set_user_token concern
@@ -22,7 +22,6 @@ module DeviseTokenAuth
22
22
  end
23
23
 
24
24
  def omniauth_success
25
-
26
25
  # find or create user by provider and provider uid
27
26
  @user = resource_name.where({
28
27
  uid: auth_hash['uid'],
@@ -1,15 +1,21 @@
1
1
  module DeviseTokenAuth::Concerns::SetUserByToken
2
2
  extend ActiveSupport::Concern
3
+ include DeviseTokenAuth::Controllers::Helpers
3
4
 
4
5
  included do
5
- before_action :set_user_by_token
6
6
  after_action :update_auth_header
7
7
  end
8
8
 
9
9
  # user auth
10
- def set_user_by_token
10
+ def set_user_by_token(mapping=nil)
11
+ # determine target authentication class
12
+ rc = resource_class(mapping)
13
+
11
14
  # no default user defined
12
- return false unless resource_class
15
+ return unless rc
16
+
17
+ # user has already been found and authenticated
18
+ return @user if @user and @user.class == rc
13
19
 
14
20
  # parse header for values necessary for authentication
15
21
  uid = request.headers['uid']
@@ -22,17 +28,19 @@ module DeviseTokenAuth::Concerns::SetUserByToken
22
28
  @client_id ||= 'default'
23
29
 
24
30
  # mitigate timing attacks by finding by uid instead of auth token
25
- @user = @current_user = uid && resource_class.find_by_uid(uid)
31
+ user = uid && rc.find_by_uid(uid)
26
32
 
27
- if @user && @user.valid_token?(@token, @client_id)
28
- sign_in(:user, @user, store: false, bypass: true)
33
+ if user && user.valid_token?(@token, @client_id)
34
+ sign_in(:user, user, store: false, bypass: true)
29
35
 
30
36
  # check this now so that the duration of the request itself doesn't eat
31
37
  # away the buffer
32
- @is_batch_request = is_batch_request?(@user, @client_id)
38
+ @is_batch_request = is_batch_request?(user, @client_id)
39
+
40
+ return @user = user
33
41
  else
34
42
  # zero all values previously set values
35
- @user = @current_user = @is_batch_request = nil
43
+ return @user = @is_batch_request = nil
36
44
  end
37
45
  end
38
46
 
@@ -59,13 +67,21 @@ module DeviseTokenAuth::Concerns::SetUserByToken
59
67
  end
60
68
  end
61
69
 
62
- def resource_class
63
- mapping = request.env['devise.mapping'] || Devise.mappings.values.first
70
+
71
+ def resource_class(m=nil)
72
+ if m
73
+ mapping = Devise.mappings[m]
74
+ else
75
+ mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
76
+ end
77
+
64
78
  mapping.to
65
79
  end
66
80
 
81
+
67
82
  private
68
83
 
84
+
69
85
  def is_batch_request?(user, client_id)
70
86
  user.tokens[client_id] and
71
87
  user.tokens[client_id]['updated_at'] and
@@ -1,7 +1,5 @@
1
1
  module DeviseTokenAuth
2
- class ConfirmationsController < Devise::ConfirmationsController
3
- include Devise::Controllers::Helpers
4
-
2
+ class ConfirmationsController < DeviseTokenAuth::ApplicationController
5
3
  def show
6
4
  @user = resource_class.confirm_by_token(params[:confirmation_token])
7
5
 
@@ -1,10 +1,6 @@
1
1
  module DeviseTokenAuth
2
- class PasswordsController < Devise::PasswordsController
3
- include Devise::Controllers::Helpers
4
- include DeviseTokenAuth::Concerns::SetUserByToken
5
-
6
- skip_before_filter :require_no_authentication
7
- skip_before_filter :set_user_by_token, :only => [:create, :edit]
2
+ class PasswordsController < DeviseTokenAuth::ApplicationController
3
+ before_filter :set_user_by_token, :only => [:update]
8
4
  skip_after_filter :update_auth_header, :only => [:create, :edit]
9
5
 
10
6
  # this action is responsible for generating password reset tokens and
@@ -17,7 +13,7 @@ module DeviseTokenAuth
17
13
  }, status: 401
18
14
  end
19
15
 
20
- unless resource_params[:redirect_url]
16
+ unless params[:redirect_url]
21
17
  return render json: {
22
18
  success: false,
23
19
  errors: ['Missing redirect url.']
@@ -32,13 +28,11 @@ module DeviseTokenAuth
32
28
  errors = nil
33
29
 
34
30
  if @user
35
- @user.update_attributes({
36
- reset_password_redirect_url: resource_params[:redirect_url]
37
- })
38
-
39
- @user = resource_class.send_reset_password_instructions({
31
+ @user.send_reset_password_instructions({
40
32
  email: resource_params[:email],
41
- provider: 'email'
33
+ provider: 'email',
34
+ redirect_url: params[:redirect_url],
35
+ client_config: params[:config_name]
42
36
  })
43
37
 
44
38
  if @user.errors.empty?
@@ -80,11 +74,12 @@ module DeviseTokenAuth
80
74
  expiry: expiry
81
75
  }
82
76
 
77
+ # ensure that user is confirmed
83
78
  @user.skip_confirmation! unless @user.confirmed_at
84
79
 
85
80
  @user.save!
86
81
 
87
- redirect_to(@user.build_auth_url(resource_params[:redirect_url], {
82
+ redirect_to(@user.build_auth_url(params[:redirect_url], {
88
83
  token: token,
89
84
  client_id: client_id,
90
85
  reset_password: true
@@ -141,7 +136,8 @@ module DeviseTokenAuth
141
136
  end
142
137
 
143
138
  def resource_params
144
- params.permit(:email, :password, :password_confirmation, :reset_password_token, :redirect_url)
139
+ params.permit(:email, :password, :password_confirmation, :reset_password_token)
145
140
  end
141
+
146
142
  end
147
143
  end
@@ -1,14 +1,6 @@
1
1
  module DeviseTokenAuth
2
- class RegistrationsController < Devise::RegistrationsController
3
- include Devise::Controllers::Helpers
4
- include DeviseTokenAuth::Concerns::SetUserByToken
5
-
6
- #prepend_before_filter :require_no_authentication, :only => [ :create, :destroy, :update ]
7
- skip_before_filter :require_no_authentication
8
- before_action :configure_devise_token_auth_permitted_parameters
9
-
10
- skip_before_filter :set_user_by_token, :only => [:create]
11
- skip_before_filter :authenticate_scope!, :only => [:destroy, :update]
2
+ class RegistrationsController < DeviseTokenAuth::ApplicationController
3
+ before_filter :set_user_by_token, :only => [:destroy, :update]
12
4
  skip_after_filter :update_auth_header, :only => [:create, :destroy]
13
5
 
14
6
  respond_to :json
@@ -18,8 +10,22 @@ module DeviseTokenAuth
18
10
  @resource.uid = sign_up_params[:email]
19
11
  @resource.provider = "email"
20
12
 
13
+ # success redirect url is required
14
+ unless params[:confirm_success_url]
15
+ return render json: {
16
+ status: 'error',
17
+ data: @resource,
18
+ errors: ["Missing `confirm_success_url` param."]
19
+ }, status: 403
20
+ end
21
+
21
22
  begin
22
23
  if @resource.save
24
+ @resource.send_confirmation_instructions({
25
+ client_config: params[:config_name],
26
+ redirect_url: params[:confirm_success_url]
27
+ })
28
+
23
29
  render json: {
24
30
  status: 'success',
25
31
  data: @resource.as_json
@@ -86,9 +92,5 @@ module DeviseTokenAuth
86
92
  def account_update_params
87
93
  params.permit(devise_parameter_sanitizer.for(:account_update))
88
94
  end
89
-
90
- def configure_devise_token_auth_permitted_parameters
91
- devise_parameter_sanitizer.for(:sign_up) << :confirm_success_url
92
- end
93
95
  end
94
96
  end
@@ -1,11 +1,7 @@
1
1
  # see http://www.emilsoman.com/blog/2013/05/18/building-a-tested/
2
2
  module DeviseTokenAuth
3
- class SessionsController < Devise::SessionsController
4
- skip_before_filter :require_no_authentication
5
- skip_before_filter :verify_signed_out_user, only: :destroy
6
-
7
- include Devise::Controllers::Helpers
8
- include DeviseTokenAuth::Concerns::SetUserByToken
3
+ class SessionsController < DeviseTokenAuth::ApplicationController
4
+ before_filter :set_user_by_token, :only => [:destroy]
9
5
 
10
6
  def create
11
7
  @user = resource_class.find_by_email(resource_params[:email])
@@ -11,7 +11,6 @@ module DeviseTokenAuth::Concerns::User
11
11
  serialize :tokens, JSON
12
12
 
13
13
  validates_presence_of :email, if: Proc.new { |u| u.provider == 'email' }
14
- validates_presence_of :confirm_success_url, if: Proc.new {|u| u.provider == 'email'}
15
14
 
16
15
  # only validate unique emails among email registration users
17
16
  validate :unique_email_user, on: :create
@@ -20,6 +19,7 @@ module DeviseTokenAuth::Concerns::User
20
19
  after_save :set_empty_token_hash
21
20
  after_initialize :set_empty_token_hash
22
21
 
22
+
23
23
  # don't use default devise email validation
24
24
  def email_required?
25
25
  false
@@ -28,9 +28,50 @@ module DeviseTokenAuth::Concerns::User
28
28
  def email_changed?
29
29
  false
30
30
  end
31
+
32
+
33
+ # override devise method to include additional info as opts hash
34
+ def send_confirmation_instructions(opts=nil)
35
+ unless @raw_confirmation_token
36
+ generate_confirmation_token!
37
+ end
38
+
39
+ opts ||= {}
40
+
41
+ # fall back to "default" config name
42
+ opts[:client_config] ||= "default"
43
+
44
+ if pending_reconfirmation?
45
+ opts[:to] = unconfirmed_email
46
+ end
47
+
48
+ send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
49
+ end
50
+
51
+
52
+ # override devise method to include additional info as opts hash
53
+ def send_reset_password_instructions(opts=nil)
54
+ token = set_reset_password_token
55
+
56
+ opts ||= {}
57
+
58
+ # fall back to "default" config name
59
+ opts[:client_config] ||= "default"
60
+
61
+ if pending_reconfirmation?
62
+ opts[:to] = unconfirmed_email
63
+ else
64
+ opts[:to] = email
65
+ end
66
+
67
+ send_devise_notification(:reset_password_instructions, token, opts)
68
+
69
+ token
70
+ end
31
71
  end
32
72
 
33
73
 
74
+
34
75
  def valid_token?(token, client_id='default')
35
76
  client_id ||= 'default'
36
77
 
@@ -44,6 +85,13 @@ module DeviseTokenAuth::Concerns::User
44
85
  end
45
86
 
46
87
 
88
+ # this must be done from the controller so that additional params
89
+ # can be passed on from the client
90
+ def send_confirmation_notification?
91
+ false
92
+ end
93
+
94
+
47
95
  def token_is_current?(token, client_id)
48
96
  return true if (
49
97
  # ensure that expiry and token are set