devise_token_auth 0.1.28.beta6 → 0.1.28.beta7

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 (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