xing_backend_token_auth 0.1.31
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 +7 -0
- data/LICENSE +13 -0
- data/README.md +679 -0
- data/Rakefile +34 -0
- data/app/controllers/devise_token_auth/application_controller.rb +22 -0
- data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +110 -0
- data/app/controllers/devise_token_auth/confirmations_controller.rb +31 -0
- data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +169 -0
- data/app/controllers/devise_token_auth/passwords_controller.rb +107 -0
- data/app/controllers/devise_token_auth/registrations_controller.rb +99 -0
- data/app/controllers/devise_token_auth/sessions_controller.rb +50 -0
- data/app/controllers/devise_token_auth/token_validations_controller.rb +22 -0
- data/app/serializers/devise_token_auth/error_messages_serializer.rb +16 -0
- data/app/serializers/devise_token_auth/resource_errors_serializer.rb +24 -0
- data/app/serializers/devise_token_auth/resource_serializer.rb +17 -0
- data/app/serializers/devise_token_auth/success_message_serializer.rb +15 -0
- data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/devise_token_auth/omniauth_failure.html.erb +2 -0
- data/app/views/devise_token_auth/omniauth_success.html.erb +8 -0
- data/app/views/layouts/omniauth_response.html.erb +31 -0
- data/config/initializers/devise.rb +207 -0
- data/config/initializers/token_auth_failure_app.rb +7 -0
- data/config/locales/devise.en.yml +59 -0
- data/config/routes.rb +5 -0
- data/lib/devise_token_auth.rb +9 -0
- data/lib/devise_token_auth/controllers/helpers.rb +129 -0
- data/lib/devise_token_auth/controllers/url_helpers.rb +8 -0
- data/lib/devise_token_auth/engine.rb +32 -0
- data/lib/devise_token_auth/models/token_authenticatable.rb +195 -0
- data/lib/devise_token_auth/rails/routes.rb +65 -0
- data/lib/generators/devise_token_auth/USAGE +31 -0
- data/lib/generators/devise_token_auth/install_generator.rb +100 -0
- data/lib/generators/devise_token_auth/install_views_generator.rb +16 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +22 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth_add_token_info_to_users.rb.erb +14 -0
- data/lib/tasks/devise_token_auth_tasks.rake +4 -0
- data/lib/xing_backend_token_auth.rb +1 -0
- data/test/controllers/demo_group_controller_test.rb +126 -0
- data/test/controllers/demo_mang_controller_test.rb +263 -0
- data/test/controllers/demo_user_controller_test.rb +262 -0
- data/test/controllers/devise_token_auth/confirmations_controller_test.rb +107 -0
- data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +144 -0
- data/test/controllers/devise_token_auth/passwords_controller_test.rb +275 -0
- data/test/controllers/devise_token_auth/registrations_controller_test.rb +405 -0
- data/test/controllers/devise_token_auth/registrations_controller_test.rb.orig +494 -0
- data/test/controllers/devise_token_auth/sessions_controller_test.rb +169 -0
- data/test/controllers/overrides/confirmations_controller_test.rb +44 -0
- data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +44 -0
- data/test/controllers/overrides/passwords_controller_test.rb +64 -0
- data/test/controllers/overrides/registrations_controller_test.rb +42 -0
- data/test/controllers/overrides/sessions_controller_test.rb +35 -0
- data/test/controllers/overrides/token_validations_controller_test.rb +38 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/logo.jpg +0 -0
- data/test/dummy/app/assets/images/omniauth-provider-settings.png +0 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +16 -0
- data/test/dummy/app/controllers/demo_group_controller.rb +13 -0
- data/test/dummy/app/controllers/demo_mang_controller.rb +12 -0
- data/test/dummy/app/controllers/demo_user_controller.rb +12 -0
- data/test/dummy/app/controllers/overrides/confirmations_controller.rb +32 -0
- data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +14 -0
- data/test/dummy/app/controllers/overrides/passwords_controller.rb +39 -0
- data/test/dummy/app/controllers/overrides/registrations_controller.rb +27 -0
- data/test/dummy/app/controllers/overrides/sessions_controller.rb +26 -0
- data/test/dummy/app/controllers/overrides/token_validations_controller.rb +23 -0
- data/test/dummy/app/controllers/registrations_controller.rb +2 -0
- data/test/dummy/app/helpers/application_helper.rb +1065 -0
- data/test/dummy/app/models/evil_user.rb +5 -0
- data/test/dummy/app/models/mang.rb +5 -0
- data/test/dummy/app/models/user.rb +20 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +8 -0
- data/test/dummy/bin/rake +8 -0
- data/test/dummy/bin/spring +18 -0
- data/test/dummy/config.ru +16 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +31 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +44 -0
- data/test/dummy/config/environments/production.rb +82 -0
- data/test/dummy/config/environments/test.rb +40 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/devise_token_auth.rb +22 -0
- data/test/dummy/config/initializers/figaro.rb +1 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/omniauth.rb +8 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +32 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config/spring.rb +1 -0
- data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +56 -0
- data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +56 -0
- data/test/dummy/db/migrate/20140829044006_add_operating_thetan_to_user.rb +6 -0
- data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +5 -0
- data/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb +57 -0
- data/test/dummy/db/schema.rb +111 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/fixtures/evil_users.yml +29 -0
- data/test/fixtures/mangs.yml +29 -0
- data/test/fixtures/users.yml +29 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/lib/generators/devise_token_auth/install_generator_test.rb +131 -0
- data/test/lib/generators/devise_token_auth/install_views_generator_test.rb +23 -0
- data/test/models/user_test.rb +81 -0
- data/test/test_helper.rb +60 -0
- metadata +320 -0
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'DeviseTokenAuth'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
task default: :test
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class ApplicationController < DeviseController
|
3
|
+
include DeviseTokenAuth::Concerns::SetUserByToken
|
4
|
+
respond_to :json
|
5
|
+
|
6
|
+
def success_message(message = nil)
|
7
|
+
serializer = DeviseTokenAuth.success_message_serializer || SuccessMessageSerializer
|
8
|
+
serializer.new(message)
|
9
|
+
end
|
10
|
+
|
11
|
+
def error_messages(*args)
|
12
|
+
serializer = DeviseTokenAuth.error_messages_serializer || ErrorMessagesSerializer
|
13
|
+
serializer.new(*args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def error_serializer(*args)
|
17
|
+
serializer = DeviseTokenAuth.error_serializer || ResourceErrorsSerializer
|
18
|
+
serializer.new(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module DeviseTokenAuth::Concerns::SetUserByToken
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
include DeviseTokenAuth::Controllers::Helpers
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :set_request_start
|
7
|
+
after_action :update_auth_header
|
8
|
+
end
|
9
|
+
|
10
|
+
# keep track of request duration
|
11
|
+
def set_request_start
|
12
|
+
@request_started_at = Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
# user auth
|
16
|
+
def set_user_by_token(mapping=nil)
|
17
|
+
|
18
|
+
# determine target authentication class
|
19
|
+
self.mapping = mapping
|
20
|
+
rc = resource_class
|
21
|
+
|
22
|
+
# no default user defined
|
23
|
+
return unless rc
|
24
|
+
|
25
|
+
# user has already been found and authenticated
|
26
|
+
return @user if @user and @user.class == rc
|
27
|
+
|
28
|
+
# parse header for values necessary for authentication
|
29
|
+
uid = request.headers['uid']
|
30
|
+
@token = request.headers['access-token']
|
31
|
+
@client_id = request.headers['client']
|
32
|
+
|
33
|
+
return false unless @token
|
34
|
+
|
35
|
+
# client_id isn't required, set to 'default' if absent
|
36
|
+
@client_id ||= 'default'
|
37
|
+
|
38
|
+
# mitigate timing attacks by finding by uid instead of auth token
|
39
|
+
user = uid && rc.find_by_uid(uid)
|
40
|
+
|
41
|
+
if user && user.valid_token?(@token, @client_id)
|
42
|
+
sign_in(resource_name, user, store: false)
|
43
|
+
return @user = user
|
44
|
+
else
|
45
|
+
# zero all values previously set values
|
46
|
+
return @user = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def update_auth_header
|
52
|
+
|
53
|
+
# cannot save object if model has invalid params
|
54
|
+
return unless @user and @user.valid? and @client_id
|
55
|
+
|
56
|
+
# Lock the user record during any auth_header updates to ensure
|
57
|
+
# we don't have write contention from multiple threads
|
58
|
+
@user.with_lock do
|
59
|
+
|
60
|
+
# determine batch request status after request processing, in case
|
61
|
+
# another processes has updated it during that processing
|
62
|
+
@is_batch_request = is_batch_request?(@user, @client_id)
|
63
|
+
|
64
|
+
auth_header = {}
|
65
|
+
|
66
|
+
if not DeviseTokenAuth.change_headers_on_each_request
|
67
|
+
auth_header = @user.build_auth_header(@token, @client_id)
|
68
|
+
|
69
|
+
# extend expiration of batch buffer to account for the duration of
|
70
|
+
# this request
|
71
|
+
elsif @is_batch_request
|
72
|
+
auth_header = @user.extend_batch_buffer(@token, @client_id)
|
73
|
+
|
74
|
+
# update Authorization response header with new token
|
75
|
+
else
|
76
|
+
auth_header = @user.create_new_auth_token(@client_id)
|
77
|
+
end
|
78
|
+
|
79
|
+
# update the response header
|
80
|
+
response.headers.merge!(auth_header)
|
81
|
+
|
82
|
+
end # end lock
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
def mapping
|
87
|
+
@mapping ||= request.env['devise.mapping'] || Devise.mappings.values.first
|
88
|
+
end
|
89
|
+
|
90
|
+
def mapping=(m)
|
91
|
+
@mapping = Devise.mappings[m]
|
92
|
+
end
|
93
|
+
|
94
|
+
def resource_class
|
95
|
+
mapping.to
|
96
|
+
end
|
97
|
+
|
98
|
+
def resource_name
|
99
|
+
mapping.name
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
|
105
|
+
def is_batch_request?(user, client_id)
|
106
|
+
user.tokens[client_id] and
|
107
|
+
user.tokens[client_id]['updated_at'] and
|
108
|
+
Time.parse(user.tokens[client_id]['updated_at']) > @request_started_at - DeviseTokenAuth.batch_request_buffer_throttle
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class ConfirmationsController < DeviseTokenAuth::ApplicationController
|
3
|
+
def show
|
4
|
+
@user = resource_class.confirm_by_token(params[:confirmation_token])
|
5
|
+
|
6
|
+
if @user and @user.id
|
7
|
+
# create client id
|
8
|
+
client_id = SecureRandom.urlsafe_base64(nil, false)
|
9
|
+
token = SecureRandom.urlsafe_base64(nil, false)
|
10
|
+
token_hash = BCrypt::Password.create(token)
|
11
|
+
expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i
|
12
|
+
|
13
|
+
@user.tokens[client_id] = {
|
14
|
+
token: token_hash,
|
15
|
+
expiry: expiry
|
16
|
+
}
|
17
|
+
|
18
|
+
@user.save!
|
19
|
+
|
20
|
+
redirect_to(@user.build_auth_url(params[:redirect_url], {
|
21
|
+
token: token,
|
22
|
+
client_id: client_id,
|
23
|
+
account_confirmation_success: true,
|
24
|
+
config: params[:config]
|
25
|
+
}))
|
26
|
+
else
|
27
|
+
raise ActionController::RoutingError.new('Not Found')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
|
3
|
+
skip_before_filter :set_user_by_token
|
4
|
+
skip_after_filter :update_auth_header
|
5
|
+
|
6
|
+
# intermediary route for successful omniauth authentication. omniauth does
|
7
|
+
# not support multiple models, so we must resort to this terrible hack.
|
8
|
+
def redirect_callbacks
|
9
|
+
# derive target redirect route from 'resource_class' param, which was set
|
10
|
+
# before authentication.
|
11
|
+
devise_mapping = request.env['omniauth.params']['resource_class'].underscore.to_sym
|
12
|
+
redirect_route = "#{Devise.mappings[devise_mapping].as_json["path_prefix"]}/#{params[:provider]}/callback"
|
13
|
+
|
14
|
+
# preserve omniauth info for success route
|
15
|
+
session['dta.omniauth.auth'] = request.env['omniauth.auth']
|
16
|
+
session['dta.omniauth.params'] = request.env['omniauth.params']
|
17
|
+
|
18
|
+
redirect_to redirect_route
|
19
|
+
end
|
20
|
+
|
21
|
+
def omniauth_success
|
22
|
+
# find or create user by provider and provider uid
|
23
|
+
@user = resource_class.where({
|
24
|
+
uid: auth_hash['uid'],
|
25
|
+
provider: auth_hash['provider']
|
26
|
+
}).first_or_initialize
|
27
|
+
|
28
|
+
# create token info
|
29
|
+
@client_id = SecureRandom.urlsafe_base64(nil, false)
|
30
|
+
@token = SecureRandom.urlsafe_base64(nil, false)
|
31
|
+
@expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i
|
32
|
+
|
33
|
+
@auth_origin_url = generate_url(omniauth_params['auth_origin_url'], {
|
34
|
+
token: @token,
|
35
|
+
client_id: @client_id,
|
36
|
+
uid: @user.uid,
|
37
|
+
expiry: @expiry
|
38
|
+
})
|
39
|
+
|
40
|
+
# set crazy password for new oauth users. this is only used to prevent
|
41
|
+
# access via email sign-in.
|
42
|
+
unless @user.id
|
43
|
+
p = SecureRandom.urlsafe_base64(nil, false)
|
44
|
+
@user.password = p
|
45
|
+
@user.password_confirmation = p
|
46
|
+
end
|
47
|
+
|
48
|
+
@user.tokens[@client_id] = {
|
49
|
+
token: BCrypt::Password.create(@token),
|
50
|
+
expiry: @expiry
|
51
|
+
}
|
52
|
+
|
53
|
+
# sync user info with provider, update/generate auth token
|
54
|
+
assign_provider_attrs(@user, auth_hash)
|
55
|
+
|
56
|
+
# assign any additional (whitelisted) attributes
|
57
|
+
extra_params = whitelisted_params
|
58
|
+
@user.assign_attributes(extra_params) if extra_params
|
59
|
+
|
60
|
+
# don't send confirmation email!!!
|
61
|
+
@user.skip_confirmation!
|
62
|
+
|
63
|
+
@user.save!
|
64
|
+
|
65
|
+
# render user info to javascript postMessage communication window
|
66
|
+
respond_to do |format|
|
67
|
+
format.html { render :layout => "omniauth_response", :template => "devise_token_auth/omniauth_success" }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# break out provider attribute assignment for easy method extension
|
73
|
+
def assign_provider_attrs(user, auth_hash)
|
74
|
+
user.assign_attributes({
|
75
|
+
nickname: auth_hash['info']['nickname'],
|
76
|
+
name: auth_hash['info']['name'],
|
77
|
+
image: auth_hash['info']['image'],
|
78
|
+
email: auth_hash['info']['email']
|
79
|
+
})
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def omniauth_failure
|
84
|
+
@error = params[:message]
|
85
|
+
|
86
|
+
respond_to do |format|
|
87
|
+
format.html { render :layout => "omniauth_response", :template => "devise_token_auth/omniauth_failure" }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# derive allowed params from the standard devise parameter sanitizer
|
93
|
+
def whitelisted_params
|
94
|
+
whitelist = devise_parameter_sanitizer.for(:sign_up)
|
95
|
+
|
96
|
+
whitelist.inject({}){|coll, key|
|
97
|
+
param = omniauth_params[key.to_s]
|
98
|
+
if param
|
99
|
+
coll[key] = param
|
100
|
+
end
|
101
|
+
coll
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
# pull resource class from omniauth return
|
106
|
+
def resource_class
|
107
|
+
if omniauth_params
|
108
|
+
omniauth_params['resource_class'].constantize
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def resource_name
|
113
|
+
resource_class
|
114
|
+
end
|
115
|
+
|
116
|
+
# this will be determined differently depending on the action that calls
|
117
|
+
# it. redirect_callbacks is called upon returning from successful omniauth
|
118
|
+
# authentication, and the target params live in an omniauth-specific
|
119
|
+
# request.env variable. this variable is then persisted thru the redirect
|
120
|
+
# using our own dta.omniauth.params session var. the omniauth_success
|
121
|
+
# method will access that session var and then destroy it immediately
|
122
|
+
# after use.
|
123
|
+
def omniauth_params
|
124
|
+
if request.env['omniauth.params']
|
125
|
+
request.env['omniauth.params']
|
126
|
+
else
|
127
|
+
@_omniauth_params ||= session.delete('dta.omniauth.params')
|
128
|
+
@_omniauth_params
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# this sesison value is set by the redirect_callbacks method. its purpose
|
133
|
+
# is to persist the omniauth auth hash value thru a redirect. the value
|
134
|
+
# must be destroyed immediatly after it is accessed by omniauth_success
|
135
|
+
def auth_hash
|
136
|
+
@_auth_hash ||= session.delete('dta.omniauth.auth')
|
137
|
+
@_auth_hash
|
138
|
+
end
|
139
|
+
|
140
|
+
# ensure that this controller responds to :devise_controller? conditionals.
|
141
|
+
# this is used primarily for access to the parameter sanitizers.
|
142
|
+
def assert_is_devise_resource!
|
143
|
+
true
|
144
|
+
end
|
145
|
+
|
146
|
+
# necessary for access to devise_parameter_sanitizers
|
147
|
+
def devise_mapping
|
148
|
+
if omniauth_params
|
149
|
+
Devise.mappings[omniauth_params['resource_class'].underscore.to_sym]
|
150
|
+
else
|
151
|
+
request.env['devise.mapping']
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def generate_url(url, params = {})
|
156
|
+
auth_url = url
|
157
|
+
|
158
|
+
# ensure that hash-bang is present BEFORE querystring for angularjs
|
159
|
+
unless url.match(/#/)
|
160
|
+
auth_url += '#'
|
161
|
+
end
|
162
|
+
|
163
|
+
# add query AFTER hash-bang
|
164
|
+
auth_url += "?#{params.to_query}"
|
165
|
+
|
166
|
+
return auth_url
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class PasswordsController < DeviseTokenAuth::ApplicationController
|
3
|
+
before_filter :set_user_by_token, :only => [:update]
|
4
|
+
skip_after_filter :update_auth_header, :only => [:create, :edit]
|
5
|
+
|
6
|
+
# this action is responsible for generating password reset tokens and
|
7
|
+
# sending emails
|
8
|
+
def create
|
9
|
+
unless resource_params[:email].present?
|
10
|
+
return render json: error_messages('You must provide an email address.'), status: 401
|
11
|
+
end
|
12
|
+
|
13
|
+
unless params[:redirect_url]
|
14
|
+
return render json: error_messages('Missing redirect url.'), status: 401
|
15
|
+
end
|
16
|
+
|
17
|
+
@user = resource_class.where({
|
18
|
+
email: resource_params[:email]
|
19
|
+
}).first
|
20
|
+
|
21
|
+
errors = nil
|
22
|
+
|
23
|
+
if @user
|
24
|
+
@user.send_reset_password_instructions({
|
25
|
+
email: resource_params[:email],
|
26
|
+
redirect_url: params[:redirect_url],
|
27
|
+
client_config: params[:config_name]
|
28
|
+
})
|
29
|
+
|
30
|
+
if @user.errors.empty?
|
31
|
+
render json: success_message(
|
32
|
+
"An email has been sent to #{@user.email} containing instructions for resetting your password."
|
33
|
+
)
|
34
|
+
else
|
35
|
+
errors = @user.errors
|
36
|
+
end
|
37
|
+
else
|
38
|
+
errors = ["Unable to find user with email '#{resource_params[:email]}'."]
|
39
|
+
end
|
40
|
+
|
41
|
+
if errors
|
42
|
+
render json: error_messages(*errors), status: 400
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# this is where users arrive after visiting the email confirmation link
|
48
|
+
def edit
|
49
|
+
@user = resource_class.reset_password_by_token({
|
50
|
+
reset_password_token: params[:reset_password_token]
|
51
|
+
})
|
52
|
+
|
53
|
+
if @user and @user.id
|
54
|
+
client_id = SecureRandom.urlsafe_base64(nil, false)
|
55
|
+
token = SecureRandom.urlsafe_base64(nil, false)
|
56
|
+
token_hash = BCrypt::Password.create(token)
|
57
|
+
expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i
|
58
|
+
|
59
|
+
@user.tokens[client_id] = {
|
60
|
+
token: token_hash,
|
61
|
+
expiry: expiry
|
62
|
+
}
|
63
|
+
|
64
|
+
# ensure that user is confirmed
|
65
|
+
@user.skip_confirmation! unless @user.confirmed_at
|
66
|
+
|
67
|
+
@user.save!
|
68
|
+
|
69
|
+
redirect_to(@user.build_auth_url(params[:redirect_url], {
|
70
|
+
token: token,
|
71
|
+
client_id: client_id,
|
72
|
+
reset_password: true,
|
73
|
+
config: params[:config]
|
74
|
+
}))
|
75
|
+
else
|
76
|
+
raise ActionController::RoutingError.new('Not Found')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def update
|
81
|
+
# make sure user is authorized
|
82
|
+
unless @user
|
83
|
+
return render json: error_messages('Unauthorized'), status: 401
|
84
|
+
end
|
85
|
+
|
86
|
+
# ensure that password params were sent
|
87
|
+
unless password_resource_params[:password] and password_resource_params[:password_confirmation]
|
88
|
+
return render json: error_messages('You must fill out the fields labeled "password" and "password confirmation".'), status: 422
|
89
|
+
end
|
90
|
+
|
91
|
+
if @user.update_attributes(password_resource_params)
|
92
|
+
return render json: resource_serializer(@user)
|
93
|
+
else
|
94
|
+
return render json: error_serializer(@user), status: 422
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def password_resource_params
|
99
|
+
devise_parameter_sanitizer.sanitize(:account_update)
|
100
|
+
end
|
101
|
+
|
102
|
+
def resource_serializer(user)
|
103
|
+
serializer = DeviseTokenAuth.password_serializer || ResourceSerializer
|
104
|
+
serializer.new(user)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|