module TCellAgent::DLP

Public Class Methods

_handle_dataexpsure_forms(request) click to toggle source
# File lib/tcell_agent/rails/dlp/process_request.rb, line 36
def self._handle_dataexpsure_forms(request)
  dataex_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
  tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
  return unless tcell_context && dataex_policy && dataex_policy.actions_for_form_parameter?

  for_params(request) do |_method, param_name, param_value|
    actions = dataex_policy.get_actions_for_form_parameter(param_name, tcell_context.route_id)
    if actions
      actions.each do |action|
        tcell_context.add_filter_for_request_parameter(param_value, action, param_name)
      end
    end
  end
end
_handle_dataexpsure_headers(request) click to toggle source
# File lib/tcell_agent/rails/dlp/process_request.rb, line 51
def self._handle_dataexpsure_headers(request)
  dataex_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
  tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
  return unless tcell_context && dataex_policy && dataex_policy.actions_for_headers?

  headers = request.env.select { |k, _v| k.start_with? 'HTTP_' }
  headers.each do |header_name, header_value|
    header_name = header_name.sub(/^HTTP_/, '').tr('_', '-')
    actions = dataex_policy.get_actions_for_header(header_name)
    next unless actions

    actions.each do |action|
      tcell_context.add_filter_for_header_value(header_value, action, header_name)
    end
  end
end
_handler_dataexposure_cookies(request) click to toggle source
# File lib/tcell_agent/rails/dlp/process_request.rb, line 68
def self._handler_dataexposure_cookies(request)
  dataex_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
  tcell_context = request.env[TCellAgent::Instrumentation::TCELL_ID]
  return unless tcell_context && dataex_policy && dataex_policy.actions_for_cookie?

  request.cookies.each do |cookie_name, cookie_value|
    actions = dataex_policy.get_actions_for_cookie(cookie_name)
    next unless actions

    actions.each do |action|
      tcell_context.add_filter_for_cookie_value(cookie_value, action, cookie_name)
    end
  end
end
for_params(request, &block) click to toggle source
# File lib/tcell_agent/rails/dlp/process_request.rb, line 29
def self.for_params(request, &block)
  get_params = request.GET
  loop_params_hash('get', get_params, &block) if get_params
  post_params = request.POST
  loop_params_hash('post', post_params, &block) if post_params
end
get_dlp_logger() click to toggle source
# File lib/tcell_agent/rails/dlp.rb, line 29
def self.get_dlp_logger
  unless defined?(@rails_dlp_logger)
    @rails_dlp_logger = TCellAgent::ModuleLogger.new(
      TCellAgent.logger, name
    )
  end

  @rails_dlp_logger
end
handle_request_dlp_parameters(request) click to toggle source
# File lib/tcell_agent/rails/dlp/process_request.rb, line 3
def self.handle_request_dlp_parameters(request)
  TCellAgent::Instrumentation.safe_block('Handling Dataexposure (request forms)') do
    _handle_dataexpsure_forms(request)
  end

  TCellAgent::Instrumentation.safe_block('Handling Dataexposure (request headers)') do
    _handle_dataexpsure_headers(request)
  end

  TCellAgent::Instrumentation.safe_block('Handling Dataexposure (request cookies)') do
    _handler_dataexposure_cookies(request)
  end
end
instrument_find_by_sql(results) click to toggle source
# File lib/tcell_agent/rails/dlp.rb, line 143
def self.instrument_find_by_sql(results)
  return if results.empty?

  if TCellAgent.configuration.should_instrument? &&
     TCellAgent.configuration.should_intercept_requests?

    dlp_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
    request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(Thread.current.object_id, {})
    tcell_context = request_env[TCellAgent::Instrumentation::TCELL_ID]

    if tcell_context
      tcell_context.database_result_sizes.push(results.size)

      if dlp_policy && dlp_policy.enabled
        first_record = results.first
        database_name = first_record.class.connection_config.fetch(:database, '*').split('/').last
        model = first_record.class
        column_names = model.columns.map(&:name)
        table_name = model.table_name

        if dlp_policy.database_discovery_enabled
          TCellAgent.discover_database_fields(
            tcell_context.route_id,
            database_name,
            '*',
            table_name,
            column_names
          )
        end

        if results.size > TCellAgent.configuration.max_data_ex_db_records_per_request
          get_dlp_logger.warn("Route (#{tcell_context.route_id}) retrieved too many records")
        end

        column_name_to_rules = column_names.each_with_object({}) do |column_name, memo|
          rules = dlp_policy.get_actions_for_table(
            database_name,
            '*',
            table_name,
            column_name,
            tcell_context.route_id
          )

          memo[column_name] = rules if rules
        end

        return if column_name_to_rules.empty?

        results[0...TCellAgent.configuration.max_data_ex_db_records_per_request].each do |record|
          column_name_to_rules.each do |column_name, rules|
            next unless rules

            rules.each do |rule|
              tcell_context.add_response_db_filter(
                record[column_name.to_sym],
                rule,
                database_name,
                '*',
                table_name,
                column_name
              )
            end
          end
        end
      end
    end
  end
end
instrument_pluck(results, column_names, model) click to toggle source
# File lib/tcell_agent/rails/dlp.rb, line 39
def self.instrument_pluck(results, column_names, model)
  return if results.empty?

  if TCellAgent.configuration.should_instrument? &&
     TCellAgent.configuration.should_intercept_requests?

    dlp_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DATALOSS)
    request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(Thread.current.object_id, {})
    tcell_context = request_env[TCellAgent::Instrumentation::TCELL_ID]

    if tcell_context
      tcell_context.database_result_sizes.push(results.size)

      if dlp_policy && dlp_policy.enabled
        database_name = model.connection_config.fetch(
          :database, '*'
        ).split('/').last
        table_name = model.table_name
        column_names = if column_names.size.zero?
                         model.columns.map(&:name)
                       else
                         column_names.map(&:to_s)
                       end

        if dlp_policy.database_discovery_enabled
          TCellAgent.discover_database_fields(
            tcell_context.route_id,
            database_name,
            '*',
            table_name,
            column_names
          )
        end

        normalized_column_names = {}
        column_name_to_rules = column_names.each_with_object({}) do |namespaced_column_name, memo|
          namespace = nil
          column_name = namespaced_column_name
          if column_name =~ /\./
            namespace, column_name = column_name.split(/\./)
          end
          normalized_column_names[namespaced_column_name] = column_name

          next unless column_name && (!namespace || namespace == table_name)

          rules = dlp_policy.get_actions_for_table(
            database_name,
            '*',
            table_name,
            column_name,
            tcell_context.route_id
          )

          memo[namespaced_column_name] = rules if rules
        end

        if results.size > TCellAgent.configuration.max_data_ex_db_records_per_request
          get_dlp_logger.warn("Route (#{tcell_context.route_id}) retrieved too many records")
        end

        return if column_name_to_rules.empty?

        # column_names.size == 1
        # results => [1, 2, 3, 4]
        # column_names.size > 1
        # results => [[1, 'email'], [2, 'email']]
        if column_names.size == 1
          results[0...TCellAgent.configuration.max_data_ex_db_records_per_request].each do |result|
            namespaced_column_name = column_names[0]
            rules = column_name_to_rules.fetch(namespaced_column_name, [])
            rules.each do |rule|
              tcell_context.add_response_db_filter(
                result,
                rule,
                database_name,
                '*',
                table_name,
                normalized_column_names[namespaced_column_name]
              )
            end
          end
        else
          results[0...TCellAgent.configuration.max_data_ex_db_records_per_request].each do |result|
            result.each_with_index do |val, index|
              namespaced_column_name = column_names[index]
              rules = column_name_to_rules.fetch(namespaced_column_name, [])
              rules.each do |rule|
                tcell_context.add_response_db_filter(
                  val,
                  rule,
                  database_name,
                  '*',
                  table_name,
                  normalized_column_names[namespaced_column_name]
                )
              end
            end
          end
        end
      end
    end
  end
end
loop_params_hash(method, param_hash, &block) click to toggle source
# File lib/tcell_agent/rails/dlp/process_request.rb, line 17
def self.loop_params_hash(method, param_hash, &block)
  param_hash.each do |param_name, param_value|
    if param_value && param_value.is_a?(Hash)
      loop_params_hash(method, param_value, &block)
    elsif !param_value || !param_value.instance_of?(String) || param_value == ''
      next
    else
      block.call(method, param_name, param_value)
    end
  end
end