fix(security): gate custom role APIs on the custom_roles feature (#15208)
Custom Roles is a premium feature, but the account's `custom_roles` flag
was never checked by the API. An account on a plan without Custom Roles
— or one whose plan was downgraded and had the flag revoked — could
still list, create, edit and delete custom roles, and could still attach
a `custom_role_id` to an agent through the agents API. Both paths now
require the feature.
## How to reproduce
1. Disable the `custom_roles` feature for an account (Super Admin →
Account → Features, or a plan downgrade).
2. `GET /api/v1/accounts/{id}/custom_roles` — returns 200 with the
account's roles instead of denying.
3. `PATCH /api/v1/accounts/{id}/agents/{agent_id}` with `custom_role_id`
— the role is assigned.
## What changed
- `Api::V1::Accounts::CustomRolesController` gains a
`ensure_custom_roles_feature_enabled` guard, matching the shape already
used by the SLA policies controller.
-
`Enterprise::Api::V1::Accounts::AgentsController#associate_agent_with_custom_role`
ignores `custom_role_id` when the feature is off, rather than writing
it.
Existing custom role assignments are deliberately left untouched — they
are evaluated at request time by `Enterprise::AccountUser#permissions`
and the conversation policy, where custom roles mostly *narrow* an
agent's scope. Dropping them on revocation would widen conversation
visibility for restricted agents, which is a separate product decision.
---------
Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com>
This commit is contained in:
committed by
GitHub
parent
7142bc43a5
commit
94d7ccf5e9
@@ -85,7 +85,7 @@ class SamlUserBuilder
|
||||
|
||||
if matching_mapping['role']
|
||||
account_user.update(role: matching_mapping['role'])
|
||||
elsif matching_mapping['custom_role_id']
|
||||
elsif matching_mapping['custom_role_id'] && account.feature_enabled?('custom_roles')
|
||||
account_user.update(custom_role_id: matching_mapping['custom_role_id'])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
class Api::V1::Accounts::CustomRolesController < Api::V1::Accounts::EnterpriseAccountsController
|
||||
before_action :ensure_custom_roles_feature_enabled
|
||||
before_action :fetch_custom_role, only: [:show, :update, :destroy]
|
||||
before_action :check_authorization
|
||||
|
||||
@@ -28,4 +29,8 @@ class Api::V1::Accounts::CustomRolesController < Api::V1::Accounts::EnterpriseAc
|
||||
def fetch_custom_role
|
||||
@custom_role = Current.account.custom_roles.find_by(id: params[:id])
|
||||
end
|
||||
|
||||
def ensure_custom_roles_feature_enabled
|
||||
raise Pundit::NotAuthorizedError unless Current.account.feature_enabled?('custom_roles')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,6 +14,10 @@ module Enterprise::Api::V1::Accounts::AgentsController
|
||||
private
|
||||
|
||||
def associate_agent_with_custom_role
|
||||
# Custom roles are a premium feature; block assigning one when the feature is disabled,
|
||||
# but still allow clearing a stale custom_role_id left over from before a downgrade.
|
||||
return if params[:custom_role_id].present? && !Current.account.feature_enabled?('custom_roles')
|
||||
|
||||
@agent.current_account_user.update!(custom_role_id: params[:custom_role_id])
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user