trainmaster 0.1.0
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 +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
|