trainmaster 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +286 -0
- data/Rakefile +38 -0
- data/app/controllers/trainmaster/application_controller.rb +9 -0
- data/app/controllers/trainmaster/sessions_controller.rb +141 -0
- data/app/controllers/trainmaster/users_controller.rb +199 -0
- data/app/helpers/trainmaster/application_helper.rb +313 -0
- data/app/helpers/trainmaster/sessions_helper.rb +4 -0
- data/app/helpers/trainmaster/users_helper.rb +4 -0
- data/app/jobs/trainmaster/sessions_cleanup_job.rb +13 -0
- data/app/mailers/application_mailer.rb +4 -0
- data/app/mailers/trainmaster/user_mailer.rb +14 -0
- data/app/models/trainmaster/session.rb +56 -0
- data/app/models/trainmaster/user.rb +77 -0
- data/app/views/layouts/mailer.html.erb +5 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/views/layouts/trainmaster/application.html.erb +14 -0
- data/app/views/trainmaster/user_mailer/email_verification.html.erb +12 -0
- data/app/views/trainmaster/user_mailer/email_verification.text.erb +13 -0
- data/app/views/trainmaster/user_mailer/password_reset.html.erb +14 -0
- data/app/views/trainmaster/user_mailer/password_reset.text.erb +15 -0
- data/config/routes.rb +10 -0
- data/db/migrate/20161120020344_create_trainmaster_users.rb +23 -0
- data/db/migrate/20161120020722_create_trainmaster_sessions.rb +11 -0
- data/lib/tasks/trainmaster_tasks.rake +4 -0
- data/lib/trainmaster.rb +10 -0
- data/lib/trainmaster/cache.rb +28 -0
- data/lib/trainmaster/engine.rb +9 -0
- data/lib/trainmaster/roles.rb +12 -0
- data/lib/trainmaster/version.rb +3 -0
- data/test/controllers/trainmaster/application_controller_test.rb +106 -0
- data/test/controllers/trainmaster/sessions_controller_test.rb +275 -0
- data/test/controllers/trainmaster/users_controller_test.rb +335 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -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 +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +34 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/assets.rb +11 -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/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/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 +4 -0
- data/test/dummy/config/secrets.yml +22 -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/trainmaster/sessions.yml +36 -0
- data/test/fixtures/trainmaster/users.yml +27 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/jobs/trainmaster/sessions_cleanup_job_test.rb +9 -0
- data/test/mailers/previews/trainmaster/user_mailer_preview.rb +6 -0
- data/test/mailers/trainmaster/user_mailer_test.rb +9 -0
- data/test/models/trainmaster/session_test.rb +26 -0
- data/test/models/trainmaster/user_test.rb +52 -0
- data/test/test_helper.rb +33 -0
- data/test/trainmaster.rb +12 -0
- metadata +327 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
require_dependency "trainmaster/application_controller"
|
2
|
+
|
3
|
+
module Trainmaster
|
4
|
+
|
5
|
+
##
|
6
|
+
# Users controller that performs CRUD on users.
|
7
|
+
#
|
8
|
+
class UsersController < ApplicationController
|
9
|
+
|
10
|
+
# All except user creation requires a session token. Note that reset
|
11
|
+
# token is also a legit session token, so :require_token will suffice.
|
12
|
+
prepend_before_action :require_auth, only: [:show, :destroy]
|
13
|
+
prepend_before_action :accept_auth, only: [:update, :create]
|
14
|
+
prepend_before_action :require_admin_auth, only: [:index]
|
15
|
+
|
16
|
+
# Some actions must have a user specified.
|
17
|
+
before_action :get_user, only: [:show, :destroy]
|
18
|
+
|
19
|
+
##
|
20
|
+
# List all users (but only works for admin user).
|
21
|
+
#
|
22
|
+
def index
|
23
|
+
@users = User.all
|
24
|
+
render json: @users, except: [:password_digest]
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Creates a new user. This action does not require any auth although it
|
29
|
+
# is optional.
|
30
|
+
#
|
31
|
+
def create
|
32
|
+
logger.debug("Create new user")
|
33
|
+
@user = User.new(user_params)
|
34
|
+
if @user.save
|
35
|
+
|
36
|
+
# Save succeeded. Render the response based on the created user.
|
37
|
+
render json: @user,
|
38
|
+
except: [:verification_token, :reset_token, :password_digest],
|
39
|
+
status: 201
|
40
|
+
|
41
|
+
# Then, issue the verification token and send the email for
|
42
|
+
# verification.
|
43
|
+
@user.issue_token(:verification_token)
|
44
|
+
@user.save
|
45
|
+
user_mailer.email_verification(@user).deliver_later
|
46
|
+
else
|
47
|
+
render_errors 400, @user.errors.full_messages
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Renders a user data.
|
53
|
+
#
|
54
|
+
def show
|
55
|
+
render json: @user, except: [:password_digest]
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Patches the user object. There are four notable operations:
|
60
|
+
#
|
61
|
+
# - issue reset token
|
62
|
+
# - issue verification token
|
63
|
+
# - change password
|
64
|
+
# - others
|
65
|
+
#
|
66
|
+
# Issuing either reset token or verification token requires NO
|
67
|
+
# authentication. However, for that reason, the request does not get any
|
68
|
+
# meaningful response. Instead, an email is sent out for either request.
|
69
|
+
#
|
70
|
+
# For changing password, there are two ways. One is to use old password
|
71
|
+
# and the other is to use reset token.
|
72
|
+
#
|
73
|
+
# Otherwise, it's a normal update operation.
|
74
|
+
#
|
75
|
+
def update
|
76
|
+
if params[:issue_reset_token] || params[:issue_verification_token]
|
77
|
+
# For issuing a reset token, one does not need an auth token. so do
|
78
|
+
# not authorize the request. For consistency, we require the id to
|
79
|
+
# be "current".
|
80
|
+
raise ApplicationController::UNAUTHORIZED_ERROR unless params[:id] == "current"
|
81
|
+
get_user_for_token()
|
82
|
+
if params[:issue_reset_token]
|
83
|
+
update_token(:reset_token)
|
84
|
+
else
|
85
|
+
update_token(:verification_token)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
get_user()
|
89
|
+
allow_password_change? if params[:password]
|
90
|
+
update_user(user_params)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Deletes a user.
|
96
|
+
#
|
97
|
+
def destroy
|
98
|
+
if @user.destroy
|
99
|
+
render body: '', status: 204
|
100
|
+
else
|
101
|
+
# :nocov:
|
102
|
+
render_error 400, @user.errors.full_messages
|
103
|
+
# :nocov:
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
|
109
|
+
##
|
110
|
+
# Override this method to app specific mailer.
|
111
|
+
#
|
112
|
+
def user_mailer
|
113
|
+
return UserMailer
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Check if password change should be allowed. Two ways to do this: one
|
118
|
+
# is to use old password or to use a valid reset token.
|
119
|
+
#
|
120
|
+
# A ApplicationController::UNAUTHORIZED_ERROR is thrown for invalid old password or
|
121
|
+
# invalid reset token
|
122
|
+
#
|
123
|
+
def allow_password_change?
|
124
|
+
if params[:old_password]
|
125
|
+
unless @user.authenticate(params[:old_password])
|
126
|
+
raise ApplicationController::UNAUTHORIZED_ERROR
|
127
|
+
end
|
128
|
+
else
|
129
|
+
unless @token == @user.reset_token
|
130
|
+
raise ApplicationController::UNAUTHORIZED_ERROR
|
131
|
+
end
|
132
|
+
end
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# This method normally updates the user using permitted params.
|
138
|
+
#
|
139
|
+
def update_user(update_user_params)
|
140
|
+
if @user.update_attributes(update_user_params)
|
141
|
+
render json: @user, except: [:password_digest]
|
142
|
+
else
|
143
|
+
render_errors 400, @user.errors.full_messages
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# This method updates user with a new reset token. Only used for this
|
149
|
+
# operation.
|
150
|
+
#
|
151
|
+
def update_token(kind)
|
152
|
+
@user.issue_token(kind)
|
153
|
+
@user.save
|
154
|
+
if kind == :reset_token
|
155
|
+
user_mailer.password_reset(@user).deliver_later
|
156
|
+
else
|
157
|
+
user_mailer.email_verification(@user).deliver_later
|
158
|
+
end
|
159
|
+
render body: '', status: 204
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
##
|
165
|
+
# This overrides the application controller's get_user method. Since
|
166
|
+
# resource object of this users controller is user, the id is
|
167
|
+
# specified in :id param.
|
168
|
+
#
|
169
|
+
def get_user
|
170
|
+
if params[:id] == "current"
|
171
|
+
raise ApplicationController::UNAUTHORIZED_ERROR if @auth_user.nil?
|
172
|
+
params[:id] = @auth_user.uuid
|
173
|
+
end
|
174
|
+
@user = find_object(User, params[:id])
|
175
|
+
authorize_for!(@user)
|
176
|
+
return @user
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# For issuing a new reset or for re-issuing a verification token, use
|
181
|
+
# this method to get user.
|
182
|
+
#
|
183
|
+
def get_user_for_token
|
184
|
+
@user = User.find_by_username(params[:username])
|
185
|
+
raise Repia::Errors::NotFound if @user.nil?
|
186
|
+
return @user
|
187
|
+
end
|
188
|
+
|
189
|
+
def user_params
|
190
|
+
# Only ADMIN can assign the attribute role. The attribute value will
|
191
|
+
# be ignored if the user is not an ADMIN.
|
192
|
+
if has_admin_auth?
|
193
|
+
params.permit(:username, :password, :password_confirmation, :role, :verified)
|
194
|
+
else
|
195
|
+
params.permit(:username, :password, :password_confirmation, :verified)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
module Trainmaster
|
2
|
+
module ApplicationHelper
|
3
|
+
include Repia::Helper::Base
|
4
|
+
|
5
|
+
# Respect the config first. If not specified, use 401 Unauthorized.
|
6
|
+
UNAUTHORIZED_ERROR = Rails.application.config.try(:unauthorized_error) ||
|
7
|
+
Repia::Errors::Unauthorized
|
8
|
+
|
9
|
+
##
|
10
|
+
# Determines if the authenticated user is admin or not.
|
11
|
+
#
|
12
|
+
def has_admin_auth?
|
13
|
+
return instance_variable_defined?(:@auth_user) &&
|
14
|
+
@auth_user.try(:role).try(:>=, Roles::ADMIN)
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Helper method to get the user object in the request, which is
|
19
|
+
# specified by :user_id parameter. There are two ways to specify the
|
20
|
+
# user id--one in the routing or the auth context.
|
21
|
+
#
|
22
|
+
# A UNAUTHORIZED_ERROR is raised if the authenticated user is
|
23
|
+
# not authorized for the specified user information.
|
24
|
+
#
|
25
|
+
# A Repia::Errors::NotFound is raised if the specified user cannot
|
26
|
+
# be found.
|
27
|
+
#
|
28
|
+
def get_user(fallback: true)
|
29
|
+
user_id = params[:user_id]
|
30
|
+
logger.debug("Attempting to get user #{user_id}")
|
31
|
+
if !user_id.nil? && user_id != "current"
|
32
|
+
@user = find_object(User, params[:user_id]) # will throw error if nil
|
33
|
+
authorize_for!(@user)
|
34
|
+
elsif fallback || user_id == "current"
|
35
|
+
@user = @auth_user
|
36
|
+
else
|
37
|
+
# :nocov:
|
38
|
+
raise Repia::Errors::NotFound, "User #{user_id} does not exist"
|
39
|
+
# :nocov:
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# :method: require_auth
|
45
|
+
#
|
46
|
+
# Requires authentication. Either token or api key must be present.
|
47
|
+
#
|
48
|
+
|
49
|
+
##
|
50
|
+
# :method: require_admin_auth
|
51
|
+
#
|
52
|
+
# Requires admin authentication. Either token or api key of admin must
|
53
|
+
# be present.
|
54
|
+
#
|
55
|
+
|
56
|
+
##
|
57
|
+
# :method: accept_auth
|
58
|
+
#
|
59
|
+
# Accepts authentication if present. Either token or api key is accepted.
|
60
|
+
#
|
61
|
+
|
62
|
+
##
|
63
|
+
# :method: require_token
|
64
|
+
#
|
65
|
+
# Requires authentication. Token must be present.
|
66
|
+
#
|
67
|
+
|
68
|
+
##
|
69
|
+
# :method: require_admin_token
|
70
|
+
#
|
71
|
+
# Requires admin authentication. Admin token must # be present.
|
72
|
+
#
|
73
|
+
|
74
|
+
##
|
75
|
+
# :method: accept_token
|
76
|
+
#
|
77
|
+
# Accepts authentication if present. Only token is accepted.
|
78
|
+
#
|
79
|
+
##
|
80
|
+
# :method: require_api_key
|
81
|
+
#
|
82
|
+
# Requires authentication. API key must be present.
|
83
|
+
#
|
84
|
+
|
85
|
+
##
|
86
|
+
# :method: require_admin_api_key
|
87
|
+
#
|
88
|
+
# Requires admin authentication. Admin api key must be present.
|
89
|
+
#
|
90
|
+
|
91
|
+
##
|
92
|
+
# :method: accept_api_key
|
93
|
+
#
|
94
|
+
# Accepts authentication if present. Only api key is accepted.
|
95
|
+
#
|
96
|
+
|
97
|
+
#
|
98
|
+
# Metaprogramming baby
|
99
|
+
#
|
100
|
+
["auth", "token", "api_key"].each do |suffix|
|
101
|
+
|
102
|
+
define_method "require_#{suffix}" do
|
103
|
+
self.method("get_#{suffix}").call
|
104
|
+
end
|
105
|
+
|
106
|
+
define_method "require_admin_#{suffix}" do
|
107
|
+
self.method("get_#{suffix}").call(required_role: Roles::ADMIN)
|
108
|
+
end
|
109
|
+
|
110
|
+
define_method "accept_#{suffix}" do
|
111
|
+
begin
|
112
|
+
self.method("get_#{suffix}").call
|
113
|
+
rescue StandardError
|
114
|
+
logger.debug("Suppressing error")
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# Determines if the user is authorized for the object. The user must be
|
122
|
+
# either the creator of the object or must be an admin or above.
|
123
|
+
#
|
124
|
+
def authorized_for?(obj)
|
125
|
+
logger.debug("Checking to see if authorized to access object")
|
126
|
+
if @auth_user.nil?
|
127
|
+
# :nocov:
|
128
|
+
return false
|
129
|
+
# :nocov:
|
130
|
+
elsif @auth_user.role >= Roles::ADMIN
|
131
|
+
return true
|
132
|
+
elsif obj.is_a? User
|
133
|
+
return obj == @auth_user
|
134
|
+
else
|
135
|
+
return obj.try(:user) == @auth_user
|
136
|
+
end
|
137
|
+
end
|
138
|
+
alias_method :authorize_for?, :authorized_for?
|
139
|
+
|
140
|
+
##
|
141
|
+
# Deprecated: use authorized_for? instead.
|
142
|
+
#
|
143
|
+
def authorized?(obj); authorized_for?(obj) end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Authorize the user for a specified object. If the user does not have
|
147
|
+
# permission, it will throw an exception. Note that it is sometimes not
|
148
|
+
# desirable to provide detailed information about authorization failure.
|
149
|
+
# Note that this will not include this detail in the exception.
|
150
|
+
#
|
151
|
+
# A UNAUTHORIZED_ERROR is raised.
|
152
|
+
#
|
153
|
+
def authorize_for!(obj)
|
154
|
+
if !authorized_for?(obj)
|
155
|
+
logger.error("User #{@auth_user.uuid} does not have permission " +
|
156
|
+
"to access #{obj}")
|
157
|
+
raise UNAUTHORIZED_ERROR, "User is not authorized"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
protected
|
162
|
+
|
163
|
+
##
|
164
|
+
# Attempts to retrieve the payload encoded in the token. It checks if
|
165
|
+
# the token is "valid" according to JWT definition and not expired.
|
166
|
+
#
|
167
|
+
# A UNAUTHORIZED_ERROR is raised if token cannot be decoded.
|
168
|
+
#
|
169
|
+
def get_token_payload(token)
|
170
|
+
|
171
|
+
# Attempt to decode without verifying. May raise DecodeError.
|
172
|
+
decoded = JWT.decode token, nil, false
|
173
|
+
payload = decoded[0]
|
174
|
+
|
175
|
+
# At this point, we know that the token is not expired and
|
176
|
+
# well formatted. Find out if the payload is well defined.
|
177
|
+
if payload.nil?
|
178
|
+
# :nocov:
|
179
|
+
logger.error("Token payload is nil: #{token}")
|
180
|
+
raise UNAUTHORIZED_ERROR, "Invalid token"
|
181
|
+
# :nocov:
|
182
|
+
end
|
183
|
+
|
184
|
+
return payload
|
185
|
+
|
186
|
+
rescue JWT::DecodeError => e
|
187
|
+
logger.error("Token decode error: #{e.message}")
|
188
|
+
raise UNAUTHORIZED_ERROR, "Invalid token"
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# Truly verifies the token and its payload. It ensures the user and
|
193
|
+
# session specified in the token payload are indeed valid. The
|
194
|
+
# required role is also checked.
|
195
|
+
#
|
196
|
+
# A UNAUTHORIZED_ERROR is thrown for all cases where token is
|
197
|
+
# invalid.
|
198
|
+
#
|
199
|
+
def verify_token(token)
|
200
|
+
logger.debug("Verifying token: #{token}")
|
201
|
+
|
202
|
+
# First get the payload of the token. This will also verify whether
|
203
|
+
# or not the token is welformed.
|
204
|
+
payload = get_token_payload(token)
|
205
|
+
|
206
|
+
# Next, the payload should define user UUID and session UUID.
|
207
|
+
user_uuid = payload["user_uuid"]
|
208
|
+
session_uuid = payload["session_uuid"]
|
209
|
+
if user_uuid.nil? || session_uuid.nil?
|
210
|
+
logger.error("User or session is not specified")
|
211
|
+
raise UNAUTHORIZED_ERROR, "Invalid token"
|
212
|
+
end
|
213
|
+
logger.debug("Token well defined: #{token}")
|
214
|
+
|
215
|
+
# But, the user UUID and session UUID better be valid too. That is,
|
216
|
+
# they must be real user and session, and the session must belong to
|
217
|
+
# the user.
|
218
|
+
auth_user = User.find_by_uuid(user_uuid)
|
219
|
+
if auth_user.nil?
|
220
|
+
# :nocov:
|
221
|
+
logger.error("Specified user doesn't exist #{user_uuid}")
|
222
|
+
raise UNAUTHORIZED_ERROR, "Invalid token"
|
223
|
+
# :nocov:
|
224
|
+
end
|
225
|
+
auth_session = Session.find_by_uuid(session_uuid)
|
226
|
+
if auth_session.nil? || auth_session.user != auth_user
|
227
|
+
logger.error("Specified session doesn't exist #{session_uuid}")
|
228
|
+
raise UNAUTHORIZED_ERROR, "Invalid token"
|
229
|
+
end
|
230
|
+
|
231
|
+
# Finally, decode the token using the secret. Also check expiration
|
232
|
+
# here too.
|
233
|
+
JWT.decode token, auth_session.secret, true
|
234
|
+
logger.debug("Token well formatted and verified. Set cache.")
|
235
|
+
|
236
|
+
# Return the corresponding session
|
237
|
+
return auth_session
|
238
|
+
|
239
|
+
rescue JWT::DecodeError => e
|
240
|
+
logger.error(e.message)
|
241
|
+
raise UNAUTHORIZED_ERROR, "Invalid token"
|
242
|
+
end
|
243
|
+
|
244
|
+
##
|
245
|
+
# Attempt to get a token for the session. Token must be specified in
|
246
|
+
# query string or part of the JSON object.
|
247
|
+
#
|
248
|
+
# Raises a UNAUTHORIZED_ERROR if cached session has less role
|
249
|
+
# than what's required.
|
250
|
+
#
|
251
|
+
def get_token(required_role: Roles::PUBLIC)
|
252
|
+
token = params[:token]
|
253
|
+
|
254
|
+
# Look up the cache. If present, use it and skip the verification.
|
255
|
+
# Use token itself (and not a session UUID) as part of the key so
|
256
|
+
# it can be considered *verified*.
|
257
|
+
@auth_session = Cache.get(kind: :session, token: token)
|
258
|
+
|
259
|
+
# Cache miss. So proceed to verify the token and get user and
|
260
|
+
# session data from database. Then set the cache for later.
|
261
|
+
if @auth_session.nil?
|
262
|
+
@auth_session = verify_token(token)
|
263
|
+
@auth_session.role # NOTE: no-op
|
264
|
+
Cache.set({kind: :session, token: token}, @auth_session)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Obtained session may not have enough permission. Check here.
|
268
|
+
if @auth_session.role < required_role
|
269
|
+
logger.error("Not enough permission (role: #{@auth_session.role})")
|
270
|
+
raise UNAUTHORIZED_ERROR, "Invalid token"
|
271
|
+
end
|
272
|
+
@auth_user = @auth_session.user
|
273
|
+
@token = @auth_session.token
|
274
|
+
return true
|
275
|
+
end
|
276
|
+
|
277
|
+
##
|
278
|
+
# Get API key from the request.
|
279
|
+
#
|
280
|
+
# Raises a UNAUTHORIZED_ERROR if API key is not valid (or not
|
281
|
+
# provided).
|
282
|
+
#
|
283
|
+
def get_api_key(required_role: Roles::PUBLIC)
|
284
|
+
api_key = params[:api_key]
|
285
|
+
if api_key.nil?
|
286
|
+
# This case is not likely, but as a safeguard in case migration
|
287
|
+
# has not gone well.
|
288
|
+
# :nocov:
|
289
|
+
raise UNAUTHORIZED_ERROR, "Invalid api key"
|
290
|
+
# :nocov:
|
291
|
+
end
|
292
|
+
auth_user = User.find_by_api_key(api_key)
|
293
|
+
if auth_user.nil? || auth_user.role < required_role
|
294
|
+
raise UNAUTHORIZED_ERROR, "Invalid api key"
|
295
|
+
end
|
296
|
+
@auth_user = auth_user
|
297
|
+
@auth_session = nil
|
298
|
+
@token = nil
|
299
|
+
return true
|
300
|
+
end
|
301
|
+
|
302
|
+
##
|
303
|
+
# Get auth data from the request. The token takes the precedence.
|
304
|
+
#
|
305
|
+
def get_auth(required_role: Roles::USER)
|
306
|
+
if params[:token]
|
307
|
+
get_token(required_role: required_role)
|
308
|
+
else
|
309
|
+
get_api_key(required_role: required_role)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|