module TCellAgent

TODO(ralba): move TCellData from instrumentation.rb here and merge both models into one and drop usage of MetaData. TCellData needs to be serializable in order to do that

See the file “LICENSE” for the full license governing this code.

This monkey patch turns off blocking for LFI/CMDI when run in CRuby specs/ test suite. The original method also depends on a Rails installation, which CRuby does not have installed.

These modules create a logger and cache it as a class variable. This is an issue in tests when you want to mock out the logger because the cached logger will hold on to the mock object from tests across rspec tests which will result in this message:

<Double “logger”> was originally created in one example but has leaked into another example and can no longer be used. rspec-mocks' doubles are designed to only last for one example, and you need to create a new one in each example you wish to use it for.module TCellAgent

These overrides will force you to mock out these specific method calls by raising an exception if they are not mocked

Constants

VERSION

Attributes

configuration[RW]
initializer_configuration[RW]

Public Class Methods

configure() { |initializer_configuration| ... } click to toggle source
# File lib/tcell_agent/configuration.rb, line 20
def self.configure
  require 'tcell_agent/config_initializer'
  self.initializer_configuration ||= ConfigInitializer.new

  yield(initializer_configuration)
rescue NoMethodError => e
  logger = TCellAgent::ModuleLogger.new(TCellAgent::RubyLogger.new, name)
  logger.error("Error configuring tcell_agent with initializers: #{e}")
end
discover_database_fields(route_id, database, schema, table, fields) click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 33
def self.discover_database_fields(route_id, database, schema, table, fields)
  thread_agent.discover_database_fields(route_id, database, schema, table, fields)
end
empty_event_queue() click to toggle source
# File spec/support/static_agent_overrides.rb, line 4
def self.empty_event_queue
  @@spec_event_queue = []
end
event_queue() click to toggle source
# File spec/support/static_agent_overrides.rb, line 8
def self.event_queue
  @@spec_event_queue
end
get_user_from_request(request) click to toggle source
# File lib/tcell_agent/rails/auth/authlogic_helper.rb, line 7
def get_user_from_request(request)
  orig_user_id = original_get_user_from_request(request)
  begin
    if request.session && request.session.key?('user_credentials_id')
      return request.session['user_credentials_id'].to_s
    end
  rescue StandardError
    return orig_user_id
  end
  orig_user_id
end
Also aliased as: original_get_user_from_request, original_get_user_from_request
logger() click to toggle source
# File lib/tcell_agent/logger.rb, line 76
def self.logger
  return @@ruby_logger unless defined?(@native_logger)

  @native_logger
end
native_logger=(native_agent) click to toggle source
# File lib/tcell_agent/logger.rb, line 82
def self.native_logger=(native_agent)
  @native_logger = NativeLogger.new(native_agent)
end
original_get_user_from_request(request)
policy(policy_type) click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 29
def self.policy(policy_type)
  thread_agent.policies.fetch(policy_type, nil)
end
report_metrics(response_time, tcell_context) click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 25
def self.report_metrics(response_time, tcell_context)
  thread_agent.report_metrics(response_time, tcell_context)
end
report_settings() click to toggle source
# File lib/tcell_agent/settings_reporter.rb, line 8
def self.report_settings
  Thread.new do
    TCellAgent::Instrumentation.safe_block('Instrumenting Server Packages') do
      event = TCellAgent::SensorEvents::ServerAgentPackagesSensorEvent.new
      TCellAgent.send_event(event)
    end

    TCellAgent::Instrumentation.safe_block('Instrumenting Native Lib Status') do
      require 'tcell_agent/rust/native_agent'

      TCellAgent.send_event(
        TCellAgent::SensorEvents::AgentSettingEvent.new(
          'native_lib_loaded',
          TCellAgent::Rust::NativeLibrary.common_lib_available?.to_s
        )
      )
    end

    if defined?(::Rails)
      TCellAgent::Instrumentation.safe_block('Instrumenting routes') do
        TCellAgent::Instrumentation::Rails.instrument_routes
      end
    end
  end
end
safe_to_check_cmdi?() click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 37
def self.safe_to_check_cmdi?
  thread_agent && thread_agent.safe_to_check_cmdi
end
send_event(event) click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 21
def self.send_event(event)
  thread_agent.queue_sensor_event(event)
end
set_thread_agent(thread_agent) click to toggle source
# File spec/support/static_agent_overrides.rb, line 16
def self.set_thread_agent(thread_agent)
  self.thread_agent = thread_agent
end
stop_agent() click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 41
def self.stop_agent
  thread_agent.stop_agent = true
end
thread_agent() click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 5
def self.thread_agent
  unless @@my_thread_agent
    @@instance_lock.synchronize do
      @@my_thread_agent ||= TCellAgent::Agent.new
    end
  end

  @@my_thread_agent
end
thread_agent=(some_agent) click to toggle source
# File lib/tcell_agent/agent/static_agent.rb, line 15
def self.thread_agent=(some_agent)
  @@instance_lock.synchronize do
    @@my_thread_agent = some_agent
  end
end

Public Instance Methods

save(&block) click to toggle source
# File lib/tcell_agent/rails/auth/authlogic.rb, line 11
def save(&block)
  return tcell_save(&block) unless TCellAgent.configuration.should_intercept_requests?

  user_logged_in_before = !user.nil?
  success = tcell_save(&block)
  user_logged_in_after = !user.nil?

  TCellAgent::Instrumentation.safe_block('Authlogic login info') do
    user_id = nil
    password = nil
    user_valid = nil
    TCellAgent::Instrumentation.safe_block('getting userid for login form') do
      user_id = send(self.class.login_field.to_sym)
    end

    request = Authlogic::Session::Base.controller.request
    tcell_data = request.env[TCellAgent::Instrumentation::TCELL_ID]

    return success unless tcell_data

    login_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LOGINFRAUD)
    if user_logged_in_before && user_logged_in_after
    # password changed or logged in as another user
    elsif !user_logged_in_before && !user_logged_in_after
      TCellAgent::Instrumentation.safe_block('checking if user is valid') do
        error_messages = errors.messages[login_field]

        user_valid = error_messages.empty?
      end

      login_policy.report_login_failure(
        user_id,
        password,
        request.env,
        user_valid,
        tcell_data
      )
    elsif !user_logged_in_before && user_logged_in_after
      tcell_data.user_id = user_id if user_id && tcell_data.user_id.nil?
      login_policy.report_login_success(
        user_id,
        request.env,
        tcell_data
      )
    end
  end

  success
end
valid_for_http_auth?() click to toggle source
# File lib/tcell_agent/rails/auth/devise.rb, line 71
def valid_for_http_auth?
  is_valid = tcell_valid_for_http_auth?

  TCellAgent::Instrumentation.safe_block('Devise set username for http basic auth') do
    tcell_data = request.env[TCellAgent::Instrumentation::TCELL_ID]
    if http_auth_hash && tcell_data
      username = http_auth_hash[http_authentication_key]
      password = http_auth_hash[:password]
      tcell_data.user_id = username if username && !tcell_data.user_id
      tcell_data.password = password if password && !tcell_data.password
    end
  end

  is_valid
end
validate(resource, &block) click to toggle source
# File lib/tcell_agent/rails/auth/devise.rb, line 88
def validate(resource, &block)
  is_valid = tcell_validate(resource, &block)
  send_event = is_valid

  # gets the first entry in the current backtrace
  # syntax suggested by rubocop to improve performance
  if caller(1..1).first.include? 'two_factor_authenticatable'
    TCellAgent.logger.debug('Not sending login success event for Devise::Strategies::TwoFactorAuthenticatable since 2fa is unsupported', 'TCellAgent::DeviseInstrumentation')
    send_event = false
  end

  TCellAgent::Instrumentation.safe_block('Devise Authenticatable Validate') do
    if send_event && TCellAgent.configuration.should_intercept_requests?
      username = nil
      (authentication_keys || []).each do |auth_key|
        attr = authentication_hash[auth_key] unless authentication_hash.nil?

        if attr
          username ||= ''
          username += attr
        end
      end

      tcell_data = request.env[TCellAgent::Instrumentation::TCELL_ID]
      return is_valid unless tcell_data

      tcell_data.user_id = username if username && tcell_data.user_id.nil?

      login_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LOGINFRAUD)
      login_policy.report_login_success(
        username,
        request.env,
        tcell_data
      )
    end
  end

  is_valid
end