-
Notifications
You must be signed in to change notification settings - Fork 72
THREESCALE-12434: Migrate from protected attributes to strong parameters - Part 2 #4249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: strong-params-part1
Are you sure you want to change the base?
Changes from 6 commits
71e6ead
0a847b7
561896a
173e7d4
a62ccba
738b0ba
3929c52
2aec247
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -43,9 +43,8 @@ def update | |||||
|
|
||||||
| preload_to_present(buyer_account) | ||||||
|
|
||||||
| buyer_account.vat_rate = params[:vat_rate].to_f if params[:vat_rate] | ||||||
| buyer_account.settings.attributes = billing_params | ||||||
| buyer_account.update_with_flattened_attributes(flat_params) | ||||||
| buyer_account.update(account_params) | ||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
|
|
||||||
| respond_with(buyer_account) | ||||||
| end | ||||||
|
|
@@ -156,7 +155,20 @@ def find_buyer_account | |||||
| end | ||||||
| end | ||||||
|
|
||||||
| def flat_params | ||||||
| super.except(:vat_rate, :id) | ||||||
| def account_params | ||||||
| defined_fields_names = current_account.defined_fields_names_for(Account) | ||||||
| allowed_attrs = defined_fields_names + %w[name] | ||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
| nested_params = { | ||||||
| extra_fields: current_account.defined_extra_fields_names_for(Account), | ||||||
| annotations: {} | ||||||
| } | ||||||
|
|
||||||
| if defined_fields_names.include?('billing_address') | ||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are two ways to set billing address: as individual fields, or as a nested hash. The test |
||||||
| allowed_attrs += %w[billing_address_name billing_address_address1 billing_address_address2 billing_address_city | ||||||
| billing_address_country billing_address_state billing_address_zip billing_address_phone] | ||||||
| nested_params[:billing_address] = %i[name address1 address2 city country state zip phone] | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not same as above?
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure to be honest... But agree to make it more consistent. |
||||||
| end | ||||||
|
|
||||||
| params.permit(*allowed_attrs, **nested_params) | ||||||
| end | ||||||
| end | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -25,31 +25,11 @@ def index | |||||
| respond_with(bought_application_plans) | ||||||
| end | ||||||
|
|
||||||
| # swagger | ||||||
| ## e = sapi.apis.add | ||||||
| ## e.path = "/admin/api/accounts/{account_id}/application_plans/{id}/buy.xml" | ||||||
| ## e.responseClass = "application" | ||||||
| ## @desc = "Creates an application for a partner on a given application plan (deprecated)." | ||||||
| ## e.description = @desc | ||||||
| # | ||||||
| ## op = e.operations.add | ||||||
| ## op.deprecated = true | ||||||
| ## op.nickname = "buyer_app_plan_buy" | ||||||
| ## op.httpMethod = "POST" | ||||||
| ## op.summary = @desc | ||||||
| # | ||||||
| ## @id = { :name => "id", :description => "ID of the application plan.", :dataType => "int", :allowMultiple => false, :required => true, :paramType => "path" } | ||||||
| # | ||||||
| ## op.parameters.add @access_token | ||||||
| ## op.parameters.add @account_id | ||||||
| ## op.parameters.add @id | ||||||
| ## op.parameters.add :name => "name", :description => "Name of the application to be created.", :dataType => "string", :allowMultiple => false, :required => true, :paramType => "query" | ||||||
| ## op.parameters.add :name => "description", :description => "Description of the application to be created.", :dataType => "string", :allowMultiple => false, :required => true, :paramType => "query" | ||||||
| # | ||||||
|
|
||||||
|
akostadinov marked this conversation as resolved.
|
||||||
| # Creates an application for a partner on a given application plan (deprecated). | ||||||
| # POST /admin/api/accounts/{account_id}/application_plans/{id}/buy.xml | ||||||
| #TODO: deprecate this, beware there are clients using it | ||||||
| def buy | ||||||
| application = buyer.buy(application_plan, application_plan_params) | ||||||
| application = buyer.buy(application_plan, contract_params) | ||||||
| respond_with(application, serialize: application_plan) | ||||||
| end | ||||||
|
|
||||||
|
|
@@ -63,8 +43,9 @@ def application_plan | |||||
| @application_plan ||= accessible_application_plans.stock.find(params[:id]) | ||||||
| end | ||||||
|
|
||||||
| def application_plan_params | ||||||
| attributes = current_account.fields.for(Cinstance) | ||||||
| params.slice(*attributes) | ||||||
| def contract_params | ||||||
| allowed_attrs = current_account.defined_fields_names_for(Cinstance) + | ||||||
| %w[user_key application_id redirect_url first_traffic_at first_daily_traffic_at] | ||||||
| params.permit(*allowed_attrs) | ||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the default fields definitions, So, in the new version these are missing (which I think is fine): On the other hand, these are added: which I am now not sure about 🤔 This is, however, a legacy endpoint that hopefully is not used by anyone, so I think it's not a big deal.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why adding
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I read this as if they were part of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe they were not allowed to be mass assigned, but then they were assigned manually somewhere else. In that case, yes, they must be permitted here. But I don't know if that was the case. Just pointing out so @mayorova can confirm.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, I've checked this, and Lines 384 to 385 in 0a34a66
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So basically something underneath sets them approved or not so we don't permit them? If they have to be set, then permitting is also fine. But whatever, if it works - fine.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, this snippet in |
||||||
| end | ||||||
| end | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,7 @@ def index | |
| # POST /admin/api/accounts/{account_id}/applications.xml | ||
| def create | ||
| application = applications.new(user_account: buyer, plan: application_plan, create_origin: "api") | ||
| application.unflattened_attributes = application_params | ||
| application.user_key = params[:user_key] if params[:user_key] | ||
| application.application_id = params[:application_id] if params[:application_id] | ||
| application.assign_attributes(application_params) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| Array(params[:application_key]).each do |key| | ||
| application.application_keys.build(value: key) | ||
|
|
@@ -35,10 +33,7 @@ def show | |
| # Application Update | ||
| # PUT /admin/api/accounts/{account_id}/applications/{id}.xml | ||
| def update | ||
| application.unflattened_attributes = flat_params | ||
| application.user_key = params[:user_key] if params[:user_key] | ||
|
|
||
| application.save | ||
| application.update(application_update_params) | ||
|
|
||
| respond_with application | ||
| end | ||
|
|
@@ -124,15 +119,13 @@ def application_plan | |
| end | ||
|
|
||
| def application_params | ||
| flat_params.slice(*application_attributes) | ||
| end | ||
|
|
||
| def application_attributes | ||
| current_account.fields.for(Cinstance) + %w|user_key application_id| | ||
| allowed_attrs = current_account.defined_fields_names_for(Cinstance) + | ||
| %w[user_key application_id redirect_url first_traffic_at first_daily_traffic_at] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| params.permit(*allowed_attrs) | ||
| end | ||
|
|
||
| def flat_params | ||
| super.except(:account_id) | ||
| def application_update_params | ||
| application_params.except(:application_id) | ||
|
akostadinov marked this conversation as resolved.
|
||
| end | ||
|
|
||
| def find_or_create_service_contract | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,13 @@ def create | |
| private | ||
|
|
||
| def user_params | ||
| flat_params.merge({signup_type: :minimal}) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
| defined_user_fields = current_account.defined_fields_names_for(User) | ||
| params.permit(*defined_user_fields, :password) | ||
|
akostadinov marked this conversation as resolved.
Outdated
|
||
| end | ||
|
|
||
| def account_params | ||
| allowed_attrs = current_account.defined_fields_names_for(Account) - %w[billing_address] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was it possible before?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to Claude, it accepted a hash before, so if we want to preserve old behavior, we must implement it like this: def account_params
allowed_attrs = current_account.defined_fields_names_for(Account) - %w[billing_address]
nested = { annotations: {} }
if current_account.defined_fields_names_for(Account).include?('billing_address')
nested[:billing_address] = %i[name address1 address2 city country state zip phone]
end
params.permit(*allowed_attrs, **nested)
endHowever, I'm fine with removing billing address entirely from the signup controller unless we know a scenario where this would be required.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made a test for signups controller in master (similar to the one for the account controller), and unfortunately, the same behavior is supported... both nested hash and individual fields work for setting billing address.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe Also
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| params.permit(*allowed_attrs, annotations: {}) | ||
| end | ||
|
|
||
| def check_creation_errors | ||
|
|
@@ -31,7 +37,7 @@ def check_creation_errors | |
| end | ||
|
|
||
| def signup_params | ||
| Signup::SignupParams.new(plans: plans, user_attributes: user_params, account_attributes: flat_params, defaults: defaults) | ||
| Signup::SignupParams.new(plans: plans, user_attributes: user_params.merge(signup_type: :minimal), account_attributes: account_params, defaults: defaults) | ||
| end | ||
|
|
||
| def defaults | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,10 +18,7 @@ def create | |||||||||
|
|
||||||||||
| authorize! :create, user | ||||||||||
|
|
||||||||||
| user.unflattened_attributes = flat_params | ||||||||||
| user.signup_type = :created_by_provider | ||||||||||
|
|
||||||||||
| user.save | ||||||||||
| user.update(user_params.merge(signup_type: :created_by_provider)) | ||||||||||
|
|
||||||||||
| respond_with(user) | ||||||||||
| end | ||||||||||
|
|
@@ -39,7 +36,7 @@ def show | |||||||||
| def update | ||||||||||
| authorize! :update, user | ||||||||||
|
|
||||||||||
| user.update_with_flattened_attributes(flat_params, as: current_user.try(:role)) | ||||||||||
| user.update(user_params) | ||||||||||
|
|
||||||||||
| respond_with(user) | ||||||||||
| end | ||||||||||
|
|
@@ -131,7 +128,11 @@ def can_create | |||||||||
|
|
||||||||||
| private | ||||||||||
|
|
||||||||||
| def flat_params | ||||||||||
| super.except(:id) | ||||||||||
| def user_params | ||||||||||
| defined_fields_names = current_account.provider_account.defined_fields_names_for(User) | ||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These endpoints are for managing the users of the provider account (
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if it would be more understandable to have it as |
||||||||||
| permission_attrs = [:member_permission_service_ids, { member_permission_service_ids: [], member_permission_ids: [] }] | ||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ideally that would be a code comment for future readers. Although I think we have tests for that so one will notice. |
||||||||||
| allowed_attrs = defined_fields_names + %w[password password_confirmation cas_identifier] | ||||||||||
| allowed_attrs += permission_attrs if provider_key.present? || current_user.admin? | ||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Permission attributes were only restricted for admin users here:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A bit worried about this, the security depends on we remembering to always add this check in all controllers that handle these attributes. Is this properly tested? If we have to add such a check in controller, why not delegating this to cancancan like we do here? porta/app/controllers/provider/admin/account/users_controller.rb Lines 61 to 64 in 71e6ead
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also thought about cancan, this role you found is really nice. The issue though is this So it will be nice to have it but I would not require it for this PR. On the other hand, previously provider_key auth was not handled, so not handling it in this PR will not be a regression. An easy fix might be to set In summary, I'm ok with all options:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But we already have a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked this. When we authenticate via What I wonder is: are we implementing all these ugly workarounds in each API controller in order to accept provider keys? This is what claude says: This project is gonna kill me.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what I told you :) that current_user is not set. But we can change the module to set first admin for example. Provider key means something like the provider root account. When you lost access to your admin for some reason, you can recover with the provider key. I think that not so many controllers check user permissions. In all of them though, we would need special logic to handle As this is not a regression though, I would suggest such improvements to be performed within another JIRA issue.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand you now. Yeah, I think setting
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't quite understand what Claude is suggesting... But here are some points:
I don't really understand how this is expected to work based on the But according to the tests, this is what happens: Indeed, if Probably, because of the missing role in So, with
I am not expecting us to add more controllers for handling these fields. Conclusion: I think the current implementation achieves the same behavior as before, so I wouldn't complicate things any more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, not in this PR. What I thought was that in case we already have or add in the future permissions checks in other controllers, it might be worth having a |
||||||||||
| params.permit(*allowed_attrs) | ||||||||||
| end | ||||||||||
| end | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,10 +30,7 @@ def new | |
| end | ||
|
|
||
| def update | ||
| vat = account_params[:vat_rate] | ||
| account.vat_rate = vat if vat # vat_rate is protected attribute | ||
|
|
||
| if account.update(account_params.except(:vat_rate)) | ||
| if account.update(account_params) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| redirect_to admin_buyers_account_path(account), success: t('.success') | ||
| else | ||
| render :edit | ||
|
|
@@ -109,13 +106,18 @@ def signup_params | |
| Signup::SignupParams.new(plans: [], user_attributes: user_params.merge(signup_type: :created_by_provider), account_attributes: account_params, validate_fields: false) | ||
| end | ||
|
|
||
| # TODO: using `permit` later | ||
| def account_params | ||
| @account_params ||= params.require(:account).except(:user) | ||
| defined_builtin_fields_names = current_account.defined_builtin_fields_names_for(Account) | ||
| defined_extra_fields_names = current_account.defined_extra_fields_names_for(Account) | ||
| allowed_attrs = defined_builtin_fields_names - %w[billing_address country] + %w[country_id] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The test |
||
| params.require(:account).permit(*allowed_attrs, extra_fields: defined_extra_fields_names) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and in other UI controllers - custom parameters (invented by the user) are submitted inside |
||
| end | ||
|
|
||
| def user_params | ||
| params.require(:account).fetch(:user, {}) | ||
| defined_builtin_fields_names = current_account.defined_builtin_fields_names_for(User) | ||
| defined_extra_fields_names = current_account.defined_extra_fields_names_for(User) | ||
| allowed_attrs = defined_builtin_fields_names + %w[password] | ||
|
akostadinov marked this conversation as resolved.
|
||
| params.require(:account).fetch(:user, {}).permit(*allowed_attrs, extra_fields: defined_extra_fields_names) | ||
| end | ||
|
|
||
| def set_plans | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,10 +22,7 @@ def show | |
| def edit; end | ||
|
|
||
| def update | ||
| # TODO: I think this controller is used only on provider side | ||
| user.validate_fields! if current_account.buyer? | ||
|
|
||
| user.attributes = user_params | ||
| user.assign_attributes(permitted_user_params) | ||
| user.role = user_params.fetch(:role, user.role) if can?(:update_role, user) | ||
|
|
||
| if user.save | ||
|
|
@@ -86,10 +83,15 @@ def find_user | |
| @user = @account.users.find(params[:id]).decorate | ||
| end | ||
|
|
||
| DEFAULT_PARAMS = %i[username email password password_confirmation role].freeze | ||
|
|
||
| def user_params | ||
| @user_params ||= params.require(:user).permit(*DEFAULT_PARAMS, extra_fields: [*user.defined_extra_fields_names]) | ||
| @user_params ||= params.require(:user) | ||
| end | ||
|
|
||
| def permitted_user_params | ||
| fields_names = current_account.defined_fields_names_for(User) | ||
| extra_fields_names = current_account.defined_extra_fields_names_for(User) | ||
| user_params.permit(*fields_names, :password, :password_confirmation, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do not need to add
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But maybe
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about this? 2aec247 |
||
| extra_fields: extra_fields_names) | ||
| end | ||
|
|
||
| def redirect_back_or_show_detail(**opts) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,9 +48,7 @@ def create | |
| # Tenant Update | ||
| # PUT /master/api/providers/{id}.xml | ||
| def update | ||
| provider_account.assign_attributes(update_params, without_protection: true) | ||
| provider_account.assign_unflattened_attributes(params.require(:account)) | ||
| provider_account.save | ||
| provider_account.update(update_account_params) | ||
|
|
||
| respond_with signup_result_with_nil_token | ||
| end | ||
|
|
@@ -117,14 +115,27 @@ def find_plan_for_upgrade | |
| render_error "Plan with ID #{plan_id.presence} not found", status: :not_found | ||
| end | ||
|
|
||
| def update_params | ||
| permitted_params = provider_account.scheduled_for_deletion? ? %i[state_event] : UPDATE_PARAMS | ||
| params.require(:account).permit(permitted_params) | ||
| end | ||
|
|
||
| def create_params | ||
| defaults = { ApplicationPlan => { :name => 'API signup', :description => 'API signup', :create_origin => 'api' } } | ||
| Signup::SignupParams.new(plans: plans, user_attributes: flat_params.merge(signup_type: :created_by_provider), account_attributes: flat_params, defaults: defaults) | ||
| Signup::SignupParams.new(plans: plans, user_attributes: user_params.merge(signup_type: :created_by_provider), account_attributes: create_account_params, defaults: defaults) | ||
| end | ||
|
|
||
| def user_params | ||
| defined_fields_names = current_account.defined_fields_names_for(User) | ||
| params.permit(*defined_fields_names, :password) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same question about |
||
| end | ||
|
|
||
| def permitted_account_attrs | ||
| current_account.defined_fields_names_for(Account) | UPDATE_PARAMS | ||
| end | ||
|
|
||
| def create_account_params | ||
| params.permit(*permitted_account_attrs) | ||
| end | ||
|
|
||
| def update_account_params | ||
| allowed_attrs = provider_account.scheduled_for_deletion? ? %i[state_event] : permitted_account_attrs | ||
| params.require(:account).permit(*allowed_attrs) | ||
| end | ||
|
|
||
| def plans | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.