forked from instructure/canvas-lms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtoken.rb
More file actions
130 lines (106 loc) · 3.88 KB
/
Copy pathtoken.rb
File metadata and controls
130 lines (106 loc) · 3.88 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
module Canvas::Oauth
class Token
attr_reader :key, :code
REDIS_PREFIX = 'oauth2:'
USER_KEY = 'user'
CLIENT_KEY = 'client_id'
SCOPES_KEY = 'scopes'
PURPOSE_KEY = 'purpose'
REMEMBER_ACCESS = 'remember_access'
def initialize(key, code, access_token=nil)
@key = key
@code = code if code
if access_token
@access_token = access_token
@user = @access_token.user
end
end
def is_for_valid_code?
code_data.present?
end
def client_id
code_data[CLIENT_KEY]
end
def user
@user ||= User.find(code_data[USER_KEY])
end
def scopes
@scopes ||= code_data[SCOPES_KEY] || []
end
def purpose
code_data[PURPOSE_KEY]
end
def remember_access?
@remember_access ||= !!code_data[REMEMBER_ACCESS]
end
def code_data
@code_data ||= JSON.parse(cached_code_entry)
end
def cached_code_entry
Canvas.redis.get("#{REDIS_PREFIX}#{code}").presence || "{}"
end
def create_access_token_if_needed(replace_tokens = false)
@access_token ||= self.class.find_reusable_access_token(user, key, scopes, purpose)
if @access_token.nil?
# Clear other tokens issued under the same developer key if requested
user.access_tokens.where(developer_key_id: key).destroy_all if replace_tokens || key.replace_tokens
# Then create a new one
@access_token = user.access_tokens.create!({
:developer_key => key,
:remember_access => remember_access?,
:scopes => scopes,
:purpose => purpose
})
@access_token.clear_full_token! if @access_token.scoped_to?(['userinfo'])
@access_token.clear_plaintext_refresh_token! if @access_token.scoped_to?(['userinfo'])
end
end
def access_token
create_access_token_if_needed
@access_token
end
def self.find_reusable_access_token(user, key, scopes, purpose)
if key.force_token_reuse
find_access_token(user, key, scopes, purpose)
elsif AccessToken.scopes_match?(scopes, ["userinfo"])
find_userinfo_access_token(user, key, purpose)
end
end
def as_json(_options={})
json = {
'access_token' => access_token.full_token,
'token_type' => 'Bearer',
'user' => user.as_json(:only => [:id, :name], :include_root => false)
}
json['refresh_token'] = access_token.plaintext_refresh_token if access_token.plaintext_refresh_token
if access_token.expires_at && key.auto_expire_tokens
json['expires_in'] = access_token.expires_at.utc.to_i - Time.now.utc.to_i
end
json
end
def self.find_userinfo_access_token(user, developer_key, purpose)
find_access_token(user, developer_key, ["userinfo"], purpose, {remember_access: true})
end
def self.find_access_token(user, developer_key, scopes, purpose, conditions = {})
user.shard.activate do
user.access_tokens.active.where({:developer_key_id => developer_key, :purpose => purpose}.merge(conditions)).detect do |token|
token.scoped_to?(scopes)
end
end
end
def self.generate_code_for(user_id, client_id, options = {})
code = SecureRandom.hex(64)
code_data = {
USER_KEY => user_id,
CLIENT_KEY => client_id,
SCOPES_KEY => options[:scopes],
PURPOSE_KEY => options[:purpose],
REMEMBER_ACCESS => options[:remember_access] }
Canvas.redis.setex("#{REDIS_PREFIX}#{code}", Setting.get('oath_token_request_timeout', 10.minutes.to_s).to_i, code_data.to_json)
return code
end
def self.expire_code(code)
Canvas.redis.del "#{REDIS_PREFIX}#{code}"
end
end
end