Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions spec/live_permissions_spec.cr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require "./helper"

module PlaceOS::Api
# sys_admin / support are capped by the user's current model, so revoking them applies
# before the JWT expires. API keys deliberately keep their own stored permissions.
# sys_admin / support come from the user's current model, not the JWT claims, so changes
# apply to existing sessions. API keys deliberately keep their own stored permissions.
describe "live user permissions" do
admin_path = ApiKeys.base_route # check_admin
support_path = Storages.base_route # check_support
Expand Down Expand Up @@ -70,16 +70,19 @@ module PlaceOS::Api
client.get(support_path, headers: headers).status_code.should eq 200
end

it "does not elevate a JWT when the user is promoted" do
it "elevates a JWT when the user is promoted" do
user = new_user.call(false, false)
headers = bearer_headers.call(user)

client.get(admin_path, headers: headers).status_code.should eq 403
client.get(support_path, headers: headers).status_code.should eq 403

user.sys_admin = true
user.support = true
user.save!

client.get(admin_path, headers: headers).status_code.should eq 403
client.get(support_path, headers: headers).status_code.should eq 403
client.get(admin_path, headers: headers).status_code.should eq 200
client.get(support_path, headers: headers).status_code.should eq 200
end

it "lets an API key grant more than its owner holds" do
Expand Down
10 changes: 5 additions & 5 deletions src/placeos-rest-api/utilities/current-user.cr
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ module PlaceOS::Api
raise JWT::Error.new("logged out")
end
@current_user = user_model
user_token = cap_permissions(user_token, user_model)
user_token = apply_user_permissions(user_token, user_model)
end

@user_token = user_token
Expand All @@ -109,14 +109,14 @@ module PlaceOS::Api
user
end

# A JWT can't grant more than the user currently holds, so revoking sys_admin or
# support applies before the token expires. Promotions still need a new token.
private def cap_permissions(token : ::PlaceOS::Model::UserJWT, user : ::PlaceOS::Model::User) : ::PlaceOS::Model::UserJWT
# The user record, not the JWT claims, decides sys_admin / support, so permission
# changes apply to existing sessions without the user signing in again.
private def apply_user_permissions(token : ::PlaceOS::Model::UserJWT, user : ::PlaceOS::Model::User) : ::PlaceOS::Model::UserJWT
held = ::PlaceOS::Model::UserJWT::Permissions::User
held |= ::PlaceOS::Model::UserJWT::Permissions::Admin if user.sys_admin
held |= ::PlaceOS::Model::UserJWT::Permissions::Support if user.support
meta = token.user
return token if meta.permissions <= held
return token if meta.permissions == held

::PlaceOS::Model::UserJWT.new(
iss: token.iss,
Expand Down
Loading