module WGU::ThycoticComms

Public Class Methods

folder_lookup(*args) click to toggle source

find a good way to remove this hardcoding of 545 parent folder id

# File lib/pps_commons/thycotic_comms.rb, line 41
def self.folder_lookup(*args)
  base_folder_id = ENV['SECRET_STORE_BASE_FOLDER']
  return base_folder_id if args.empty?
  query = args[0] || base_folder_id
  parent_folder_query = args[1]

  params = if query.to_s[/^\d+$/]
    ["api/v1/folders/#{query}"]
  else
    params_hash = { 'filter.searchText' => query }

    unless parent_folder_query.nil?
      params_hash['filter.parentFolder'] = parent_folder_query
    end

    ["api/v1/folders/lookup", params_hash]
  end

  self.get(*params)['records']
end
get(url, params = {}) click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 8
def self.get(url, params = {})
  res = nil
  retry_count = 0
  refresh_token = self.get_api_key
  query_url = "#{url}?" + params.map { |k,v| "#{k}=#{v}&" }.join.gsub(/\&$/, '')
  query_url = self.ss_url(query_url)
  begin
    RestClient.get(query_url,{ Authorization: "Bearer #{refresh_token}" })
    res = RestClient.get(
      query_url,
      { Authorization: "Bearer #{refresh_token}" }
    )
  rescue RestClient::Unauthorized => e
    retry_count += 1
    refresh_token = self.update_tmp_pass!
    retry unless retry_count > 1
    raise e
  end

  JSON.parse(res.body)
end
get_secret(query, folder_name) click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 30
def self.get_secret(query, folder_name)
  secret_id_res = self.secret_lookup(query, folder_name)
  secret_id_res.empty? ? { 'items' => [] } : self.secret_lookup(secret_id_res.first['id'])
end
getter(term, body) click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 35
def self.getter(term, body)
  tupple = body['items'].find { |field| field['fieldName'][/^#{term}$/i] }
  tupple['itemValue'] unless tupple.nil?
end
secret_lookup(secret_query, folder_query = nil) click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 62
def self.secret_lookup(secret_query, folder_query = nil)
  folder_id = if folder_query.to_s[/^\d+$/]
    folder_query
  else
    res = self.folder_lookup(folder_query)
    res.nil? ? self.folder_lookup : res.first['id']
  end

  secret_params = if secret_query.to_s[/^\d+$/]
    ["api/v1/secrets/#{secret_query}"]
  else
    params_hash = if secret_query.kind_of?(String)
      {
        'filter.folderId' => folder_id,
        'filter.searchText' => secret_query
      }
    else
      { 'filter.parentFolderId' => folder_id }.merge(secret_query)
    end

    ['api/v1/secrets/lookup', params_hash]
  end

  result = self.get(*secret_params)
  result.include?('records') ? result['records'] : result
end

Private Class Methods

cache_client() click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 90
def self.cache_client
  @cache_client ||= Aws::S3::Client.new(
    region:             ENV['AWS_REGION'],
    access_key_id:      ENV['ACCESS_KEY_ID'],
    secret_access_key:  ENV['SECRET_ACCESS_KEY']
  )
end
cache_key() click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 163
def self.cache_key
  begin
    self.cache_client.get_object(
      bucket: ENV['PPS_PASS_CACHE'],
      key: 'secret_store_refresh_token'
    ).body.read
  rescue Aws::S3::Errors::NoSuchKey => e
    self.update_tmp_pass!
  end
end
get_api_key() click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 159
def self.get_api_key
  self.cache_key || self.get_new_key
end
get_new_key() click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 174
def self.get_new_key
  user = self.cache_client.get_object(
      bucket: ENV['PPS_PASS_CACHE'],
      key: ENV['SECRET_STORE_USERNAME']
  ).body.read
  pass = self.cache_client.get_object(
    bucket: ENV['PPS_PASS_CACHE'],
    key: ENV['SECRET_STORE_PASSWORD']
  ).body.read
  res = RestClient.post(
    self.ss_url(URI(ENV['SECRET_STORE_TOKEN'])),
    {
      'username' => user,
      'password' => pass,
      'grant_type' => 'password'
    },
    {
      content_type: "application/x-www-form-urlencoded",
      'cache-control' => 'no-cache'
    }
  )

  JSON.parse(res.body)['access_token']
end
ss_url(path = '') click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 199
def self.ss_url(path = '')
  URI(URI(ENV['SECRET_STORE_BASE_URL']) + URI(path)).to_s
end
update_tmp_pass!() click to toggle source
# File lib/pps_commons/thycotic_comms.rb, line 98
def self.update_tmp_pass!
  cache_lock = nil
  retry_count = 0
  lock_file = 'locks/secret_store_refresh_token.lock'
  key_file = 'secret_store_refresh_token'
  bucket = Aws::S3::Bucket.new(
    client: self.cache_client,
    name: ENV['PPS_PASS_CACHE'],
    versioning_configuration: {
      mfa_delete: "Disabled",
      status: "Enabled"
    }
  )
  my_cache_lock = bucket.put_object(bucket: bucket.name, key: lock_file)
  self.cache_client
    .wait_until(:object_exists, bucket: bucket.name, key: lock_file)
  first_version =
    self.cache_client.get_object(bucket: bucket.name, key: lock_file)

  if my_cache_lock.version_id.eql?(first_version.version_id)
    key = self.get_new_key
    self.cache_client.put_object({
      body: key,
      bucket: bucket.name,
      key: key_file
    })

    bucket.put_object(key: key_file, body: key)
    retry_count_for_suspend = 0
    begin
      bucket.versioning.suspend
    rescue Exception => e
      retry_count_for_suspend += 1
      sleep 3
      retry unless retry_count_for_suspend > 3
      raise e
    end
    my_cache_lock.delete
    bucket.object_versions(prefix: lock_file) do |version|
      self.cache_client.delete_object(
        bucket: bucket.name,
        key: lock_file,
        version_id: version.id
      )
    end
    bucket.versioning.enable
    key
  else
    should_stop = -> (retries) do
      bucket.objects(prefix: lock_file).count.eql?(0) || retries > 20
    end

    until should_stop.call(retry_count)
      retry_count += 1
      sleep 3
    end

    self.cached_key
  end
end