Skip to content
Open
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
2 changes: 1 addition & 1 deletion app/access/private_domain_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def read_for_update?(private_domain, _params=nil)

def update?(private_domain, _params=nil)
return true if admin_user?
return false if private_domain.in_suspended_org?
return false if private_domain.in_suspended_or_deleting_org?

private_domain.owning_organization.managers.include?(context.user)
end
Expand Down
2 changes: 1 addition & 1 deletion app/access/process_model_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def index_with_token?(_)

def create?(app, _params=nil)
return true if admin_user?
return false if app.in_suspended_org?
return false if app.in_suspended_or_deleting_org? || app.space&.suspended_or_deleting?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helper method? app.in_suspended_or_deleting_space?


app.space&.has_developer?(context.user)
end
Expand Down
2 changes: 1 addition & 1 deletion app/access/route_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def index_with_token?(_)

def can_write_to_route(route, is_create=false)
return true if context.queryer.can_write_globally?
return false if route.in_suspended_org?
return false if route.in_suspended_or_deleting_org? || route.space.suspended_or_deleting?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helper method? route.in_suspended_or_deleting_space?

Why not route.space&?

return false if route.wildcard_host? && route.domain.shared?

FeatureFlag.raise_unless_enabled!(:route_creation) if is_create
Expand Down
6 changes: 4 additions & 2 deletions app/access/route_mapping_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ def index_with_token?(_)

def create?(route_mapping, _params=nil)
return true if admin_user?
return false if route_mapping.route.in_suspended_org?

route_mapping.route.space.has_developer?(context.user)
space = route_mapping.route.space
return false if space.in_suspended_or_deleting_org? || space.suspended_or_deleting?

space.has_developer?(context.user)
end

def read_for_update?(route_mapping, _params=nil)
Expand Down
6 changes: 3 additions & 3 deletions app/access/service_instance_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ def create?(service_instance, _params=nil)
return true if admin_user?

FeatureFlag.raise_unless_enabled!(:service_instance_creation)
return false if service_instance.in_suspended_org?
return false if service_instance.in_suspended_or_deleting_org? || service_instance.space&.suspended_or_deleting?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helper method? service_instance.in_suspended_or_deleting_space?


service_instance.space&.has_developer?(context.user) && allowed?(service_instance)
end

def read_for_update?(service_instance, _params=nil)
return true if admin_user?
return false if service_instance.in_suspended_org?
return false if service_instance.in_suspended_or_deleting_org? || service_instance.space&.suspended_or_deleting?

service_instance.space&.has_developer?(context.user)
end
Expand All @@ -74,7 +74,7 @@ def update?(service_instance, params=nil)

def delete?(service_instance)
return true if admin_user?
return false if service_instance.in_suspended_org?
return false if service_instance.in_suspended_or_deleting_org? || service_instance.space&.suspended_or_deleting?

service_instance.space&.has_developer?(context.user)
end
Expand Down
6 changes: 4 additions & 2 deletions app/access/service_key_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ def index_with_token?(_)

def create?(service_key, _params=nil)
return true if admin_user?
return false if service_key.in_suspended_org?

service_key.service_instance.space.has_developer?(context.user)
space = service_key.service_instance.space
return false if space.in_suspended_or_deleting_org? || space.suspended_or_deleting?

space.has_developer?(context.user)
end

def delete?(service_key)
Expand Down
4 changes: 2 additions & 2 deletions app/access/space_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def read_related_object_for_update?(space, params=nil)

def create?(space, _params=nil)
return true if context.queryer.can_write_globally?
return false if space.in_suspended_org?
return false if space.in_suspended_or_deleting_org? || space.suspended_or_deleting?

context.queryer.can_write_to_active_org?(space.organization_id)
end
Expand All @@ -57,7 +57,7 @@ def can_remove_related_object?(space, params)

def read_for_update?(space, _params=nil)
return true if context.queryer.can_write_globally?
return false if space.in_suspended_org?
return false if space.in_suspended_or_deleting_org? || space.suspended_or_deleting?

context.queryer.can_write_to_active_org?(space.organization_id) || context.queryer.can_update_active_space?(space.id, space.organization_id)
end
Expand Down
2 changes: 1 addition & 1 deletion app/access/space_quota_definition_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def index_with_token?(_)

def create?(space_quota_definition, _params=nil)
return true if admin_user?
return false if space_quota_definition.organization.suspended?
return false if space_quota_definition.organization.suspended_or_deleting?

space_quota_definition.organization.managers.include?(context.user)
end
Expand Down
1 change: 1 addition & 0 deletions app/actions/organization_update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def update(org, message)
AnnotationsUpdate.update(org, message.annotations, OrganizationAnnotationModel)

if message.requested?(:suspended)
error!("Organization '#{org.name}' is being deleted and cannot be reactivated.") if org.deleting? && message.suspended == false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no check for setting a DELETING org to SUSPENDED. I think this should also be forbidden.

org.status = message.suspended ? Organization::SUSPENDED : Organization::ACTIVE
end

Expand Down
6 changes: 5 additions & 1 deletion app/actions/space_create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ def initialize(user_audit_info:)
def create(org, message)
space = nil
Space.db.transaction do
space = VCAP::CloudController::Space.create(name: message.name, organization: org)
space = VCAP::CloudController::Space.create(
name: message.name,
organization: org,
status: message.suspended ? Space::SUSPENDED : Space::ACTIVE
)
MetadataUpdate.update(space, message)
Repositories::SpaceEventRepository.new.record_space_create(space, user_audit_info, message.audit_hash)
end
Expand Down
4 changes: 4 additions & 0 deletions app/actions/space_update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ def update(space, message)
space.db.transaction do
space.lock!
space.name = message.name if message.requested?(:name)
if message.requested?(:suspended)
error!("Space '#{space.name}' is being deleted and cannot be reactivated.") if space.deleting? && message.suspended == false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no check for setting a DELETING space to SUSPENDED. I think this should also be forbidden.

space.status = message.suspended ? Space::SUSPENDED : Space::ACTIVE
end
MetadataUpdate.update(space, message)

space.save
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/runtime/route_mappings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def create
raise CloudController::Errors::ApiError.new_from_details('RouteNotFound', request_attrs['route_guid']) unless route
raise CloudController::Errors::ApiError.new_from_details('AppNotFound', request_attrs['app_guid']) unless process
raise CloudController::Errors::ApiError.new_from_details('NotAuthorized') unless permissions.can_write_to_active_space?(process.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.is_space_active?(process.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.writable_space_state(process.space.id) == :active

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This raises OrgSuspended also for a suspended space or a deleting org/space. Not sure if we want to fix this for the v2 controllers (app/controllers/runtime/route_mappings_controller.rb and app/controllers/services/service_bindings_controller.rb)?


route_mapping = V2::RouteMappingCreate.new(UserAuditInfo.from_context(SecurityContext), route, process, request_attrs, logger).add

Expand All @@ -61,7 +61,7 @@ def delete(guid)

raise CloudController::Errors::ApiError.new_from_details('RouteMappingNotFound', guid) unless route_mapping
raise CloudController::Errors::ApiError.new_from_details('NotAuthorized') unless permissions.can_write_to_active_space?(route_mapping.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.is_space_active?(route_mapping.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.writable_space_state(route_mapping.space.id) == :active

RouteMappingDelete.new(UserAuditInfo.from_context(SecurityContext)).delete(route_mapping)

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/services/service_bindings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def create
raise CloudController::Errors::ApiError.new_from_details('AppNotFound', @request_attrs['app_guid']) unless app
raise CloudController::Errors::ApiError.new_from_details('ServiceInstanceNotFound', @request_attrs['service_instance_guid']) unless service_instance
raise CloudController::Errors::ApiError.new_from_details('NotAuthorized') unless permissions.can_write_to_active_space?(app.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.is_space_active?(app.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.writable_space_state(app.space.id) == :active

creator = ServiceBindingCreate.new(UserAuditInfo.from_context(SecurityContext))
service_binding = creator.create(app, service_instance, message, volume_services_enabled?, accepts_incomplete)
Expand Down Expand Up @@ -95,7 +95,7 @@ def delete(guid)

raise CloudController::Errors::ApiError.new_from_details('ServiceBindingNotFound', guid) unless service_binding
raise CloudController::Errors::ApiError.new_from_details('NotAuthorized') unless permissions.can_write_to_active_space?(service_binding.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.is_space_active?(service_binding.space.id)
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended') unless permissions.writable_space_state(service_binding.space.id) == :active

accepts_incomplete = convert_flag_to_bool(params['accepts_incomplete'])

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/v3/app_features_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def update
else
unauthorized! unless permission_queryer.can_write_to_active_space?(space.id)
end
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

message = VCAP::CloudController::AppFeatureUpdateMessage.new(hashed_params['body'])
unprocessable!(message.errors.full_messages) unless message.valid?
Expand Down
35 changes: 35 additions & 0 deletions app/controllers/v3/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def suspended!
raise CloudController::Errors::ApiError.new_from_details('OrgSuspended')
end

def space_suspended!
raise CloudController::Errors::ApiError.new_from_details('SpaceSuspended')
end

def resource_being_deleted!(resource_name)
raise CloudController::Errors::ApiError.new_from_details('ResourceBeingDeleted', resource_name)
end

def resource_not_found_with_message!(message)
raise CloudController::Errors::ApiError.new_from_details('ResourceNotFound', message)
end
Expand Down Expand Up @@ -150,6 +158,33 @@ def permission_queryer
@permission_queryer ||= VCAP::CloudController::Permissions.new(VCAP::CloudController::SecurityContext.current_user)
end

def require_writable_org!(org)
require_writable_org_id!(org.id)
end

def require_writable_org_id!(org_id)
case permission_queryer.writable_org_state(org_id)
when :active
nil
when :deleting
resource_being_deleted!('organization')
when :suspended
suspended!
end
Comment on lines +166 to +173

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would look more compact to me. Does Rubocop complain then?

org_state = permission_queryer.writable_org_state(org_id)
resource_being_deleted!('organization') if org_state == :deleting
suspended! if org_state == :suspended

end

def require_writable_space!(space)
org_state = permission_queryer.writable_org_state(space.organization_id)
return resource_being_deleted!('organization') if org_state == :deleting

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These return statements are not needed. Do we use this pattern elsewhere? And without return we can skip the empty lines (maybe keep one before permission_queryer.writable_space_state).


space_state = permission_queryer.writable_space_state(space.id)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass org_state as optional parameter, so that writable_space_state does not fetch it again. This reduces the total number of DB statements issued by require_writable_space! from 3 to 2.

return resource_being_deleted!('space') if space_state == :deleting

return suspended! if org_state == :suspended

space_suspended! if space_state == :suspended
end

def add_warning_headers(warnings)
return if warnings.nil?
raise ArgumentError.new('warnings should be an array') unless warnings.is_a?(Array)
Expand Down
18 changes: 9 additions & 9 deletions app/controllers/v3/apps_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def create
space = Space.where(guid: message.space_guid).first
unprocessable_space! unless space && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unauthorized! unless permission_queryer.can_write_to_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)
FeatureFlag.raise_unless_enabled!(:diego_docker) if message.lifecycle_type == VCAP::CloudController::PackageModel::DOCKER_TYPE
lifecycle = AppLifecycleProvider.provide_for_create(message)
FeatureFlag.raise_unless_enabled!(:diego_cnb) if lifecycle.type == VCAP::CloudController::Lifecycles::CNB
Expand Down Expand Up @@ -123,7 +123,7 @@ def update

app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unauthorized! unless permission_queryer.can_write_to_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

lifecycle = AppLifecycleProvider.provide_for_update(message, app)
unprocessable!(lifecycle.errors.full_messages) unless lifecycle.valid?
Expand Down Expand Up @@ -152,7 +152,7 @@ def destroy

app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unauthorized! unless permission_queryer.can_write_to_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

delete_action = AppDelete.new(user_audit_info)
deletion_job = VCAP::CloudController::Jobs::DeleteActionJob.new(AppModel, app.guid, delete_action)
Expand All @@ -169,7 +169,7 @@ def start
app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unprocessable_lacking_droplet! unless app.droplet
unauthorized! unless permission_queryer.can_manage_apps_in_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

FeatureFlag.raise_unless_enabled!(:diego_docker) if app.lifecycle_type == DockerLifecycleDataModel::LIFECYCLE_TYPE
FeatureFlag.raise_unless_enabled!(:diego_cnb) if app.lifecycle_type == CNBLifecycleDataModel::LIFECYCLE_TYPE
Expand All @@ -191,7 +191,7 @@ def stop
app, space = AppFetcher.new.fetch(hashed_params[:guid])
app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unauthorized! unless permission_queryer.can_manage_apps_in_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

AppStop.stop(app:, user_audit_info:)
TelemetryLogger.v3_emit(
Expand All @@ -212,7 +212,7 @@ def restart
app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unprocessable_lacking_droplet! unless app.droplet
unauthorized! unless permission_queryer.can_manage_apps_in_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

FeatureFlag.raise_unless_enabled!(:diego_docker) if app.lifecycle_type == DockerLifecycleDataModel::LIFECYCLE_TYPE
FeatureFlag.raise_unless_enabled!(:diego_cnb) if app.lifecycle_type == CNBLifecycleDataModel::LIFECYCLE_TYPE
Expand All @@ -237,7 +237,7 @@ def clear_buildpack_cache
app, space = AppFetcher.new.fetch(hashed_params[:guid])
app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unauthorized! unless permission_queryer.can_delete_buildpack_cache?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

delete_job = Jobs::V3::BuildpackCacheDelete.new(app.guid)
job = Jobs::Enqueuer.new(queue: Jobs::Queues.generic).enqueue_pollable(delete_job)
Expand Down Expand Up @@ -299,7 +299,7 @@ def update_environment_variables

app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unauthorized! unless permission_queryer.can_manage_apps_in_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)

message = UpdateEnvironmentVariablesMessage.new(hashed_params[:body])
unprocessable!(message.errors.full_messages) unless message.valid?
Expand All @@ -317,7 +317,7 @@ def assign_current_droplet

app_not_found! unless app && permission_queryer.can_read_from_space?(space.id, space.organization_id)
unauthorized! unless permission_queryer.can_manage_apps_in_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)
deployment_in_progress! if app.deploying?

AppAssignDroplet.new(user_audit_info).assign(app, droplet)
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/v3/builds_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ def create

package = PackageModel.where(guid: message.package_guid).
eager(:app, :space, space: :organization, app: %i[buildpack_lifecycle_data cnb_lifecycle_data]).first
unprocessable_package! unless package &&
permission_queryer.can_manage_apps_in_active_space?(package.space.id) && permission_queryer.is_space_active?(package.space.id)
unprocessable_package! unless package && permission_queryer.can_manage_apps_in_active_space?(package.space.id)
require_writable_space!(package.space) if package

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if package is not needed, this would already be an unprocessable_package!.


FeatureFlag.raise_unless_enabled!(:diego_docker) if package.type == PackageModel::DOCKER_TYPE

Expand Down Expand Up @@ -98,7 +98,7 @@ def update
unauthorized! unless permission_queryer.can_update_build_state?
else
unauthorized! unless permission_queryer.can_write_to_active_space?(space.id)
suspended! unless permission_queryer.is_space_active?(space.id)
require_writable_space!(space)
end

build = BuildUpdate.new.update(build, create_valid_update_message)
Expand Down
16 changes: 8 additions & 8 deletions app/controllers/v3/deployments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ def create
message = DeploymentCreateMessage.new(hashed_params[:body])
unprocessable!(message.errors.full_messages) unless message.valid?

unable_to_use = 'Unable to use app. Ensure that the app exists and you have access to it and the organization is not suspended.'
unable_to_use = 'Unable to use app. Ensure that the app exists and you have access to it.'
app = AppModel.find(guid: message.app_guid)

unprocessable!(unable_to_use) unless app && permission_queryer.can_manage_apps_in_active_space?(app.space.id) &&
permission_queryer.is_space_active?(app.space.id)
unprocessable!(unable_to_use) unless app && permission_queryer.can_manage_apps_in_active_space?(app.space.id)
require_writable_space!(app.space)
unprocessable!('Cannot create deployment from a revision for an app without revisions enabled') if message.revision_guid && !app.revisions_enabled

begin
Expand Down Expand Up @@ -80,7 +80,7 @@ def update

resource_not_found!(:deployment) unless deployment && permission_queryer.can_read_from_space?(deployment.app.space.id, deployment.app.space.organization_id)
unauthorized! unless permission_queryer.can_write_to_active_space?(deployment.app.space.id)
suspended! unless permission_queryer.is_space_active?(deployment.app.space.id)
require_writable_space!(deployment.app.space)

message = VCAP::CloudController::DeploymentUpdateMessage.new(hashed_params[:body])
unprocessable!(message.errors.full_messages) unless message.valid?
Expand All @@ -93,8 +93,8 @@ def update
def cancel
deployment = DeploymentModel.find(guid: hashed_params[:guid])

resource_not_found!(:deployment) unless deployment && permission_queryer.can_manage_apps_in_active_space?(deployment.app.space.id) &&
permission_queryer.is_space_active?(deployment.app.space.id)
resource_not_found!(:deployment) unless deployment && permission_queryer.can_manage_apps_in_active_space?(deployment.app.space.id)
require_writable_space!(deployment.app.space)

begin
DeploymentCancel.cancel(deployment:, user_audit_info:)
Expand All @@ -109,8 +109,8 @@ def cancel
def continue
deployment = DeploymentModel.find(guid: hashed_params[:guid])

resource_not_found!(:deployment) unless deployment && permission_queryer.can_manage_apps_in_active_space?(deployment.app.space.id) &&
permission_queryer.is_space_active?(deployment.app.space.id)
resource_not_found!(:deployment) unless deployment && permission_queryer.can_manage_apps_in_active_space?(deployment.app.space.id)
require_writable_space!(deployment.app.space)

begin
DeploymentContinue.continue(deployment:, user_audit_info:)
Expand Down
Loading
Loading