/
set_user_by_token.rb
107 lines (77 loc) · 2.92 KB
/
set_user_by_token.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
module DeviseTokenAuth::Concerns::SetUserByToken
extend ActiveSupport::Concern
include DeviseTokenAuth::Controllers::Helpers
included do
before_action :set_request_start
after_action :update_auth_header
end
# keep track of request duration
def set_request_start
@request_started_at = Time.now
end
# user auth
def set_user_by_token(mapping=nil)
# determine target authentication class
rc = resource_class(mapping)
# no default user defined
return unless rc
# user has already been found and authenticated
return @resource if @resource and @resource.class == rc
# parse header for values necessary for authentication
uid = request.headers['uid'] || params['uid']
@token = request.headers['access-token'] || params['access-token']
@client_id = request.headers['client'] || params['client']
return false unless @token
# client_id isn't required, set to 'default' if absent
@client_id ||= 'default'
# mitigate timing attacks by finding by uid instead of auth token
user = uid && rc.find_by_uid(uid)
if user && user.valid_token?(@token, @client_id)
sign_in(:user, user, store: false, bypass: true)
return @resource = user
else
# zero all values previously set values
return @resource = nil
end
end
def update_auth_header
# cannot save object if model has invalid params
return unless @resource and @resource.valid? and @client_id
# Lock the user record during any auth_header updates to ensure
# we don't have write contention from multiple threads
@resource.with_lock do
# determine batch request status after request processing, in case
# another processes has updated it during that processing
@is_batch_request = is_batch_request?(@resource, @client_id)
auth_header = {}
if not DeviseTokenAuth.change_headers_on_each_request
auth_header = @resource.build_auth_header(@token, @client_id)
# update the response header
response.headers.merge!(auth_header)
# extend expiration of batch buffer to account for the duration of
# this request
elsif @is_batch_request
auth_header = @resource.extend_batch_buffer(@token, @client_id)
# update Authorization response header with new token
else
auth_header = @resource.create_new_auth_token(@client_id)
# update the response header
response.headers.merge!(auth_header)
end
end # end lock
end
def resource_class(m=nil)
if m
mapping = Devise.mappings[m]
else
mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
end
mapping.to
end
private
def is_batch_request?(user, client_id)
user.tokens[client_id] and
user.tokens[client_id]['updated_at'] and
Time.parse(user.tokens[client_id]['updated_at']) > @request_started_at - DeviseTokenAuth.batch_request_buffer_throttle
end
end