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.
- checksums.yaml +4 -4
- data/README.md +274 -77
- data/app/controllers/devise_token_auth/auth_controller.rb +4 -1
- data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +8 -2
- data/app/controllers/devise_token_auth/confirmations_controller.rb +1 -1
- data/app/controllers/devise_token_auth/passwords_controller.rb +3 -3
- data/app/controllers/devise_token_auth/registrations_controller.rb +1 -1
- data/app/controllers/devise_token_auth/sessions_controller.rb +1 -1
- data/app/models/{user.rb → devise_token_auth/concerns/user.rb} +28 -23
- data/config/initializers/devise.rb +4 -64
- data/config/routes.rb +2 -14
- data/lib/devise_token_auth/engine.rb +5 -1
- data/lib/devise_token_auth/rails/routes.rb +36 -0
- data/lib/devise_token_auth/version.rb +1 -1
- data/lib/generators/devise_token_auth/USAGE +23 -5
- data/lib/generators/devise_token_auth/install_generator.rb +69 -5
- data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +5 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +56 -0
- data/lib/generators/devise_token_auth/templates/user.rb +3 -0
- data/test/controllers/demo_controller_test.rb +39 -4
- data/test/controllers/devise_token_auth/auth_controller_test.rb +98 -0
- data/test/controllers/devise_token_auth/confirmations_controller_test.rb +37 -2
- data/test/controllers/devise_token_auth/passwords_controller_test.rb +38 -2
- data/test/controllers/devise_token_auth/registrations_controller_test.rb +31 -4
- data/test/controllers/devise_token_auth/sessions_controller_test.rb +32 -0
- data/test/dummy/app/assets/images/omniauth-provider-settings.png +0 -0
- data/test/dummy/app/models/mang.rb +3 -0
- data/test/dummy/app/models/user.rb +3 -0
- data/test/dummy/config/initializers/devise_token_auth.rb +5 -0
- data/test/dummy/config/routes.rb +16 -1
- data/test/dummy/db/development.sqlite3 +0 -0
- 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
- data/test/dummy/db/migrate/{20140714223034_devise_token_auth_create_users.rb → 20140715061805_devise_token_auth_create_mangs.rb} +7 -7
- data/test/dummy/db/schema.rb +35 -4
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +7601 -0
- data/test/dummy/log/test.log +128490 -0
- data/test/fixtures/mangs.yml +31 -0
- data/test/test_helper.rb +13 -9
- 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 =
|
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 &&
|
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
|
|
@@ -23,7 +23,7 @@ module DeviseTokenAuth
|
|
23
23
|
}, status: 401
|
24
24
|
end
|
25
25
|
|
26
|
-
@user =
|
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 =
|
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 =
|
67
|
+
@user = resource_class.reset_password_by_token({
|
68
68
|
reset_password_token: resource_params[:reset_password_token]
|
69
69
|
})
|
70
70
|
|
@@ -8,7 +8,7 @@ module DeviseTokenAuth
|
|
8
8
|
respond_to :json
|
9
9
|
|
10
10
|
def create
|
11
|
-
@user =
|
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
|
-
|
2
|
-
|
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
|
-
|
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
|
-
|
11
|
-
validates_presence_of :confirm_success_url, if: Proc.new {|u| u.provider == 'email'}
|
11
|
+
serialize :tokens, JSON
|
12
12
|
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
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
|
-
#
|
230
|
-
|
231
|
-
|
232
|
-
|
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
|
-
|
2
|
-
|
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,9 +1,27 @@
|
|
1
1
|
Description:
|
2
|
-
|
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
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
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", "
|
15
|
-
say_status("skipped", "Migration '
|
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
|
-
|
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
|