devise_token_auth 0.1.20 → 0.1.21.alpha1

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +274 -77
  3. data/app/controllers/devise_token_auth/auth_controller.rb +4 -1
  4. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +8 -2
  5. data/app/controllers/devise_token_auth/confirmations_controller.rb +1 -1
  6. data/app/controllers/devise_token_auth/passwords_controller.rb +3 -3
  7. data/app/controllers/devise_token_auth/registrations_controller.rb +1 -1
  8. data/app/controllers/devise_token_auth/sessions_controller.rb +1 -1
  9. data/app/models/{user.rb → devise_token_auth/concerns/user.rb} +28 -23
  10. data/config/initializers/devise.rb +4 -64
  11. data/config/routes.rb +2 -14
  12. data/lib/devise_token_auth/engine.rb +5 -1
  13. data/lib/devise_token_auth/rails/routes.rb +36 -0
  14. data/lib/devise_token_auth/version.rb +1 -1
  15. data/lib/generators/devise_token_auth/USAGE +23 -5
  16. data/lib/generators/devise_token_auth/install_generator.rb +69 -5
  17. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +5 -0
  18. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +56 -0
  19. data/lib/generators/devise_token_auth/templates/user.rb +3 -0
  20. data/test/controllers/demo_controller_test.rb +39 -4
  21. data/test/controllers/devise_token_auth/auth_controller_test.rb +98 -0
  22. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +37 -2
  23. data/test/controllers/devise_token_auth/passwords_controller_test.rb +38 -2
  24. data/test/controllers/devise_token_auth/registrations_controller_test.rb +31 -4
  25. data/test/controllers/devise_token_auth/sessions_controller_test.rb +32 -0
  26. data/test/dummy/app/assets/images/omniauth-provider-settings.png +0 -0
  27. data/test/dummy/app/models/mang.rb +3 -0
  28. data/test/dummy/app/models/user.rb +3 -0
  29. data/test/dummy/config/initializers/devise_token_auth.rb +5 -0
  30. data/test/dummy/config/routes.rb +16 -1
  31. data/test/dummy/db/development.sqlite3 +0 -0
  32. data/{lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb → test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb} +0 -0
  33. data/test/dummy/db/migrate/{20140714223034_devise_token_auth_create_users.rb → 20140715061805_devise_token_auth_create_mangs.rb} +7 -7
  34. data/test/dummy/db/schema.rb +35 -4
  35. data/test/dummy/db/test.sqlite3 +0 -0
  36. data/test/dummy/log/development.log +7601 -0
  37. data/test/dummy/log/test.log +128490 -0
  38. data/test/fixtures/mangs.yml +31 -0
  39. data/test/test_helper.rb +13 -9
  40. metadata +22 -8
@@ -19,8 +19,11 @@ module DeviseTokenAuth
19
19
  end
20
20
 
21
21
  def omniauth_success
22
+ # pull resource class from omniauth return
23
+ resource = request.env['omniauth.params']['resource_class'].constantize
24
+
22
25
  # find or create user by provider and provider uid
23
- @user = User.where({
26
+ @user = resource.where({
24
27
  uid: auth_hash['uid'],
25
28
  provider: auth_hash['provider']
26
29
  }).first_or_initialize
@@ -6,7 +6,6 @@ module DeviseTokenAuth::Concerns::SetUserByToken
6
6
  after_action :update_auth_header
7
7
  end
8
8
 
9
-
10
9
  # user auth
11
10
  def set_user_by_token
12
11
  auth_header = request.headers["Authorization"]
@@ -14,6 +13,9 @@ module DeviseTokenAuth::Concerns::SetUserByToken
14
13
  # missing auth token
15
14
  return false unless auth_header
16
15
 
16
+ # no default user defined
17
+ return false unless resource_class
18
+
17
19
  # parse header for values necessary for authentication
18
20
  uid = auth_header[/uid=(.*?)$/,1]
19
21
  @token = auth_header[/token=(.*?) /,1]
@@ -23,7 +25,7 @@ module DeviseTokenAuth::Concerns::SetUserByToken
23
25
  @client_id ||= 'default'
24
26
 
25
27
  # mitigate timing attacks by finding by uid instead of auth token
26
- @user = @current_user = uid && User.find_by_uid(uid)
28
+ @user = @current_user = uid && resource_class.find_by_uid(uid)
27
29
 
28
30
  if @user && @user.valid_token?(@token, @client_id)
29
31
  sign_in(:user, @user, store: false, bypass: true)
@@ -61,6 +63,10 @@ module DeviseTokenAuth::Concerns::SetUserByToken
61
63
  response.headers["Authorization"] = auth_header if auth_header
62
64
  end
63
65
 
66
+ def resource_class
67
+ mapping = request.env['devise.mapping'] || Devise.mappings.values.first
68
+ mapping.to
69
+ end
64
70
 
65
71
  private
66
72
 
@@ -3,7 +3,7 @@ module DeviseTokenAuth
3
3
  include Devise::Controllers::Helpers
4
4
 
5
5
  def show
6
- @user = User.confirm_by_token(params[:confirmation_token])
6
+ @user = resource_class.confirm_by_token(params[:confirmation_token])
7
7
 
8
8
  if @user and @user.id
9
9
  # create client id
@@ -23,7 +23,7 @@ module DeviseTokenAuth
23
23
  }, status: 401
24
24
  end
25
25
 
26
- @user = User.where({
26
+ @user = resource_class.where({
27
27
  email: resource_params[:email],
28
28
  provider: 'email'
29
29
  }).first
@@ -35,7 +35,7 @@ module DeviseTokenAuth
35
35
  reset_password_redirect_url: resource_params[:redirect_url]
36
36
  })
37
37
 
38
- @user = User.send_reset_password_instructions({
38
+ @user = resource_class.send_reset_password_instructions({
39
39
  email: resource_params[:email],
40
40
  provider: 'email'
41
41
  })
@@ -64,7 +64,7 @@ module DeviseTokenAuth
64
64
 
65
65
  # this is where users arrive after visiting the email confirmation link
66
66
  def edit
67
- @user = User.reset_password_by_token({
67
+ @user = resource_class.reset_password_by_token({
68
68
  reset_password_token: resource_params[:reset_password_token]
69
69
  })
70
70
 
@@ -7,7 +7,7 @@ module DeviseTokenAuth
7
7
  respond_to :json
8
8
 
9
9
  def create
10
- @resource = User.new(resource_params)
10
+ @resource = resource_class.new(resource_params)
11
11
  @resource.uid = resource_params[:email]
12
12
  @resource.provider = "email"
13
13
 
@@ -8,7 +8,7 @@ module DeviseTokenAuth
8
8
  respond_to :json
9
9
 
10
10
  def create
11
- @user = User.find_by_email(resource_params[:email])
11
+ @user = resource_class.find_by_email(resource_params[:email])
12
12
 
13
13
  if @user and valid_params? and @user.valid_password?(resource_params[:password]) and @user.confirmed?
14
14
  # create client id
@@ -1,21 +1,26 @@
1
- class User < ActiveRecord::Base
2
- # Include default devise modules. Others available are:
3
- # :confirmable, :lockable, :timeoutable and :omniauthable
4
- devise :database_authenticatable, :registerable,
5
- :recoverable, :rememberable, :trackable, :validatable,
6
- :confirmable
1
+ module DeviseTokenAuth::Concerns::User
2
+ extend ActiveSupport::Concern
7
3
 
8
- serialize :tokens, JSON
4
+ included do
5
+ # Include default devise modules. Others available are:
6
+ # :confirmable, :lockable, :timeoutable and :omniauthable
7
+ devise :database_authenticatable, :registerable,
8
+ :recoverable, :rememberable, :trackable, :validatable,
9
+ :confirmable
9
10
 
10
- validates_presence_of :email, if: Proc.new { |u| u.provider == 'email' }
11
- validates_presence_of :confirm_success_url, if: Proc.new {|u| u.provider == 'email'}
11
+ serialize :tokens, JSON
12
12
 
13
- # only validate unique emails among email registration users
14
- validate :unique_email_user, on: :create
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
+
16
+ # only validate unique emails among email registration users
17
+ validate :unique_email_user, on: :create
18
+
19
+ # can't set default on text fields in mysql, simulate here instead.
20
+ after_save :set_empty_token_hash
21
+ after_initialize :set_empty_token_hash
22
+ end
15
23
 
16
- # can't set default on text fields in mysql, simulate here instead.
17
- after_save :set_empty_token_hash
18
- after_initialize :set_empty_token_hash
19
24
 
20
25
  def valid_token?(token, client_id='default')
21
26
  client_id ||= 'default'
@@ -94,13 +99,6 @@ class User < ActiveRecord::Base
94
99
  end
95
100
 
96
101
 
97
- def generate_url(url, params = {})
98
- uri = URI(url)
99
- uri.query = params.to_query
100
- uri.to_s
101
- end
102
-
103
-
104
102
  def extend_batch_buffer(token, client_id)
105
103
  self.tokens[client_id]['updated_at'] = Time.now
106
104
  self.save!
@@ -109,7 +107,14 @@ class User < ActiveRecord::Base
109
107
  end
110
108
 
111
109
 
112
- private
110
+ protected
111
+
112
+
113
+ def generate_url(url, params = {})
114
+ uri = URI(url)
115
+ uri.query = params.to_query
116
+ uri.to_s
117
+ end
113
118
 
114
119
 
115
120
  def serializable_hash(options={})
@@ -126,7 +131,7 @@ class User < ActiveRecord::Base
126
131
 
127
132
 
128
133
  def unique_email_user
129
- if provider == 'email' and User.where(provider: 'email', email: email).count > 0
134
+ if provider == 'email' and self.class.where(provider: 'email', email: email).count > 0
130
135
  errors.add(:email, "This email address is already in use")
131
136
  end
132
137
  end
@@ -188,71 +188,11 @@ Devise.setup do |config|
188
188
  # change their passwords.
189
189
  config.reset_password_within = 6.hours
190
190
 
191
- # ==> Configuration for :encryptable
192
- # Allow you to use another encryption algorithm besides bcrypt (default). You can use
193
- # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
194
- # :authlogic_sha512 (then you should set stretches above to 20 for default behavior)
195
- # and :restful_authentication_sha1 (then you should set stretches to 10, and copy
196
- # REST_AUTH_SITE_KEY to pepper).
197
- #
198
- # Require the `devise-encryptable` gem when using anything other than bcrypt
199
- # config.encryptor = :sha512
200
-
201
- # ==> Scopes configuration
202
- # Turn scoped views on. Before rendering "sessions/new", it will first check for
203
- # "users/sessions/new". It's turned off by default because it's slower if you
204
- # are using only default views.
205
- # config.scoped_views = false
206
-
207
- # Configure the default scope given to Warden. By default it's the first
208
- # devise role declared in your routes (usually :user).
209
- # config.default_scope = :user
210
-
211
- # Set this configuration to false if you want /users/sign_out to sign out
212
- # only the current scope. By default, Devise signs out all scopes.
213
- # config.sign_out_all_scopes = true
214
-
215
- # ==> Navigation configuration
216
- # Lists the formats that should be treated as navigational. Formats like
217
- # :html, should redirect to the sign in page when the user does not have
218
- # access, but formats like :xml or :json, should return 401.
219
- #
220
- # If you have any extra navigational formats, like :iphone or :mobile, you
221
- # should add them to the navigational formats lists.
222
- #
223
- # The "*/*" below is required to match Internet Explorer requests.
224
- # config.navigational_formats = ['*/*', :html]
225
-
226
191
  # The default HTTP method used to sign out a resource. Default is :delete.
227
192
  config.sign_out_via = :delete
228
193
 
229
- # ==> OmniAuth
230
- # Add a new OmniAuth provider. Check the wiki for more information on setting
231
- # up on your models and hooks.
232
- # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
233
-
234
- # ==> Warden configuration
235
- # If you want to use other strategies, that are not supported by Devise, or
236
- # change the failure app, you can configure them inside the config.warden block.
237
- #
238
- # config.warden do |manager|
239
- # manager.intercept_401 = false
240
- # manager.default_strategies(scope: :user).unshift :some_external_strategy
241
- # end
242
-
243
- # ==> Mountable engine configurations
244
- # When using Devise inside an engine, let's call it `MyEngine`, and this engine
245
- # is mountable, there are some extra configurations to be taken into account.
246
- # The following options are available, assuming the engine is mounted as:
247
- #
248
- # mount MyEngine, at: '/my_engine'
249
- #
250
- # The router that invoked `devise_for`, in the example above, would be:
251
- config.router_name = :devise_token_auth
252
- config.parent_controller = "DeviseTokenAuth::ApplicationController"
253
-
254
- #
255
- # When using omniauth, Devise cannot automatically set Omniauth path,
256
- # so you need to do it manually. For the users scope, it would be:
257
- #config.omniauth_path_prefix = ''
194
+ # mounted routes will point to this
195
+ Rails.application.config.after_initialize do
196
+ ::OmniAuth::config.path_prefix = config.omniauth_path_prefix = DeviseTokenAuth.omniauth_prefix
197
+ end
258
198
  end
data/config/routes.rb CHANGED
@@ -1,15 +1,3 @@
1
- DeviseTokenAuth::Engine.routes.draw do
2
- devise_for :users,
3
- :class_name => "User",
4
- :module => :devise,
5
- :path => "",
6
- :controllers => {:sessions => "devise_token_auth/sessions",
7
- :registrations => "devise_token_auth/registrations",
8
- :passwords => "devise_token_auth/passwords",
9
- :confirmations => "devise_token_auth/confirmations"}
10
-
11
- get "validate_token", to: "auth#validate_token"
12
- get "failure", to: "auth#omniauth_failure"
13
- get ":provider/callback", to: "auth#omniauth_success"
14
- post ":provider/callback", to: "auth#omniauth_success"
1
+ Rails.application.routes.draw do
2
+ get "#{::OmniAuth::config.path_prefix}/:provider/callback", to: 'devise_token_auth/auth#omniauth_success'
15
3
  end
@@ -1,3 +1,5 @@
1
+ require 'devise_token_auth/rails/routes'
2
+
1
3
  module DeviseTokenAuth
2
4
  class Engine < ::Rails::Engine
3
5
  isolate_namespace DeviseTokenAuth
@@ -5,11 +7,13 @@ module DeviseTokenAuth
5
7
 
6
8
  mattr_accessor :change_headers_on_each_request,
7
9
  :token_lifespan,
8
- :batch_request_buffer_throttle
10
+ :batch_request_buffer_throttle,
11
+ :omniauth_prefix
9
12
 
10
13
  self.change_headers_on_each_request = true
11
14
  self.token_lifespan = 2.weeks
12
15
  self.batch_request_buffer_throttle = 5.seconds
16
+ self.omniauth_prefix = '/omniauth'
13
17
 
14
18
  def self.setup(&block)
15
19
  yield self
@@ -0,0 +1,36 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+ def mount_devise_token_auth_for(resource, opts)
4
+ scope opts[:at] do
5
+ devise_for resource.pluralize.underscore.to_sym,
6
+ :class_name => resource,
7
+ :module => :devise,
8
+ :path => "",
9
+ :controllers => {:sessions => "devise_token_auth/sessions",
10
+ :registrations => "devise_token_auth/registrations",
11
+ :passwords => "devise_token_auth/passwords",
12
+ :confirmations => "devise_token_auth/confirmations"}
13
+
14
+ devise_scope resource.underscore.to_sym do
15
+ get "validate_token", to: "devise_token_auth/auth#validate_token"
16
+ get "failure", to: "devise_token_auth/auth#omniauth_failure"
17
+ get ":provider/callback", to: "devise_token_auth/auth#omniauth_success"
18
+ post ":provider/callback", to: "devise_token_auth/auth#omniauth_success"
19
+
20
+ # preserve the resource class thru oauth authentication by setting name of
21
+ # resource as "resource_class" param
22
+ match ":provider", to: redirect{|params, request|
23
+ # get the current querystring
24
+ qs = CGI::parse(request.env["QUERY_STRING"])
25
+
26
+ # append name of current resource
27
+ qs["resource_class"] = [resource]
28
+
29
+ # re-construct the path for omniauth
30
+ "#{::OmniAuth::config.path_prefix}/#{params[:provider]}?#{{}.tap {|hash| qs.each{|k, v| hash[k] = v.first}}.to_param}"
31
+ }, via: [:get]
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,3 @@
1
1
  module DeviseTokenAuth
2
- VERSION = "0.1.20"
2
+ VERSION = "0.1.21.alpha1"
3
3
  end
@@ -1,9 +1,27 @@
1
1
  Description:
2
- This generator will install all the necessary configuration and migration files for the devies_token_auth gem
2
+ This generator will install all the necessary configuration and migration
3
+ files for the devies_token_auth gem. See
4
+ https://github.com/lynndylanhurley/devise_token_auth for more information.
5
+
6
+ Arguments:
7
+ USER_CLASS # The name of the class to use for user authentication. Default is
8
+ # 'User'
9
+ MOUNT_PATH # The path at which to mount the authentication routes. Default is
10
+ # 'auth'. More detail documentation is here:
11
+ # https://github.com/lynndylanhurley/devise_token_auth#usage
3
12
 
4
13
  Example:
5
- rails generate devise_token_auth:install
14
+ rails generate devise_token_auth:install User auth
15
+
16
+ This will create:
17
+ config/initializers/devise_token_auth.rb
18
+ db/migrate/<%= Time.now.utc.strftime("%Y%m%d%H%M%S") %>_create_devise_token_auth_create_users.rb
19
+ app/models/user.rb
20
+
21
+ If 'app/models/user.rb' already exists, the following line will be inserted
22
+ after the class definition:
23
+ include DeviseTokenAuth::Concerns::User
6
24
 
7
- This will create:
8
- config/initializers/devise_token_auth.rb
9
- db/migrate/xxxxxxxx_create_devise_token_auth_user.rb
25
+ The following line will be inserted at the top of 'config/routes.rb' if it
26
+ does not already exist:
27
+ mount_devise_token_auth_for "User", at: '/auth'
@@ -4,17 +4,63 @@ module DeviseTokenAuth
4
4
 
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
 
7
- desc "This generator creates an initializer file at config/initializers/devise_token_auth.rb"
7
+ argument :user_class, type: :string, default: "User"
8
+ argument :mount_path, type: :string, default: '/auth'
9
+
8
10
  def create_initializer_file
9
11
  copy_file("devise_token_auth.rb", "config/initializers/devise_token_auth.rb")
10
12
  end
11
13
 
12
- desc "This generator creates a user migration file at db/migrate/<%= migration_id %>_devise_token_auth_create_users.rb"
13
14
  def copy_migrations
14
- if self.class.migration_exists?("db/migrate", "devise_token_auth_create_users")
15
- say_status("skipped", "Migration 'devise_token_auth' already exists")
15
+ if self.class.migration_exists?("db/migrate", "devise_token_auth_create_#{ user_class.underscore }")
16
+ say_status("skipped", "Migration 'devise_token_auth_create_#{ user_class.underscore }' already exists")
17
+ else
18
+ migration_template(
19
+ "devise_token_auth_create_users.rb.erb",
20
+ "db/migrate/devise_token_auth_create_#{ user_class.pluralize.underscore }.rb"
21
+ )
22
+ end
23
+ end
24
+
25
+ def create_user_model
26
+ fname = "app/models/#{ user_class.underscore }.rb"
27
+ unless File.exist?(fname)
28
+ template("user.rb", fname)
29
+ else
30
+ inclusion = "include DeviseTokenAuth::Concerns::User"
31
+ unless parse_file_for_line(fname, inclusion)
32
+ inject_into_file fname, after: "class #{user_class} < ActiveRecord::Base\n" do <<-'RUBY'
33
+ include DeviseTokenAuth::Concerns::User
34
+ RUBY
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def add_route_mount
41
+ f = "config/routes.rb"
42
+ str = "mount_devise_token_auth_for '#{user_class}', at: '#{mount_path}'"
43
+ line = parse_file_for_line(f, "mount_devise_token_auth_for")
44
+
45
+ unless line
46
+ line = "Rails.application.routes.draw do"
47
+ existing_user_class = false
16
48
  else
17
- migration_template("devise_token_auth_create_users.rb", "db/migrate/devise_token_auth_create_users.rb")
49
+ existing_user_class = true
50
+ end
51
+
52
+ if parse_file_for_line(f, str)
53
+ say_status("skipped", "Routes already exist for #{user_class} at #{mount_path}")
54
+ else
55
+ insert_after_line(f, line, str)
56
+
57
+ if existing_user_class
58
+ scoped_routes = ""+
59
+ "as :#{user_class.underscore} do\n"+
60
+ " # Define routes for #{user_class} within this block.\n"+
61
+ " end\n"
62
+ insert_after_line(f, str, scoped_routes)
63
+ end
18
64
  end
19
65
  end
20
66
 
@@ -23,5 +69,23 @@ module DeviseTokenAuth
23
69
  def self.next_migration_number(path)
24
70
  Time.now.utc.strftime("%Y%m%d%H%M%S")
25
71
  end
72
+
73
+ def insert_after_line(filename, line, str)
74
+ gsub_file filename, /(#{Regexp.escape(line)})/mi do |match|
75
+ "#{match}\n #{str}"
76
+ end
77
+ end
78
+
79
+ def parse_file_for_line(filename, str)
80
+ match = false
81
+ File.open(filename) do |f|
82
+ f.each_line do |line|
83
+ if line =~ /(#{Regexp.escape(str)})/mi
84
+ match = line
85
+ end
86
+ end
87
+ end
88
+ match
89
+ end
26
90
  end
27
91
  end