class Credential

Attributes

config_file_path[RW]
password[RW]
pkey_password[RW]
snowflakes[RW]
sudo_password[RW]
username[RW]

Public Class Methods

new(username, password, pkey_password, regenerate, debug) click to toggle source
# File lib/credential.rb, line 4
def initialize(username, password, pkey_password, regenerate, debug)
  @debug            = debug
  @util             = Util.new(@debug)

  @config_file_path = "#{%x{echo ~}.chomp}/.ssh/multissh.yaml"
  @username         = set_username(username)
  @password         = set_password(password)
  @pkey_password    = pkey_password
  @sudo_password    = nil
  @snowflakes       = nil
  @regenerate       = true if regenerate

  generate_config if @regenerate
  process_config
end

Public Instance Methods

generate_config() click to toggle source
# File lib/credential.rb, line 101
def generate_config
  @util.dbg('starting generation process')
  unless @regenerate
    puts    "\n\n\n\n"
    puts    "* No existing configuration file found at path: ".red + "#{@config_file_path}".yellow
    puts    "*"
    puts    "* MultiSSH handles [sudo] prompts and private key failures by storing your credentials in its config file"
    puts    "* The owner of this config file will be set to #{@username.green} with a mode of #{'600'.green}"
    puts    "*"
    puts    "* If you opt out, you will be prompted for your password on every run"
    puts    "*"
    printf  "* Would you like MultiSSH to store your credentials? (y/n): "
    ans = gets.chomp.downcase
    @util.dbg(ans)
    until ['y','n'].include? ans
      printf "Please answer only with 'y' or 'n': "
      ans = gets.chomp.downcase
    end
    generate = (ans == 'y') ? true : false

  else
    generate = true
    puts 'MultiSSH called with "--regenerate_config", generating new configuration file'
  end

  if generate
    credential = generate_credential_entry
    @yaml = { "enabled" => true, "credentials" => { @username => credential } }
  else
    @yaml = { "enabled" => false }
  end

  save_config
  set_secure_permissions

  unless generate then puts "configuration file set to disabled" end

  puts "Configuration file saved to #{@config_file_path}".yellow
  @util.dbg('end generation process')
end
generate_credential_entry() click to toggle source
# File lib/credential.rb, line 163
def generate_credential_entry
  @util.dbg("generating new entry for #{@username}")
  print "#{@username} - Password: "
  password = STDIN.noecho(&:gets).chomp
  epassword = @util.encrypt(password)
  puts "\n"

  unless ssh_agent_loaded?
    pkey_password = nil
    if private_key_exist?
      print "#{@username} - SSH Private Key Password: "
      pkey_password = STDIN.noecho(&:gets).chomp
      epkey_password = @util.encrypt(pkey_password)
      puts "\n"
    end
  end

  credential = { "password" => epassword, "pkey_password" => epkey_password }
  @util.dbg("credential:")
  @util.dbg(credential)
  return credential
end
load_config() click to toggle source
# File lib/credential.rb, line 191
def load_config
  @util.dbg("loading config from '#{@config_file_path}'")
  @yaml = YAML.load_file(@config_file_path)
end
private_key_exist?() click to toggle source
# File lib/credential.rb, line 155
def private_key_exist?
  if !Dir.glob("#{%x{echo ~}.chomp}/.ssh/id_*").empty?
    false
  else
    true
  end
end
process_config() click to toggle source
# File lib/credential.rb, line 21
def process_config
  if File.exist? @config_file_path
    @util.dbg('configuration file exists')
  else
    @util.dbg('couldnt find configuration file')
    generate_config
  end

  begin
    @yaml = YAML.load_file(@config_file_path)
  rescue
    raise 'Configuration file detected but unable to properly load. Please regenerate using "multissh.rb --regenerate_config"'
  end

  if @yaml['enabled']
    @util.dbg('credential enabled')
    @util.dbg(@yaml)

    unless @yaml['credentials'][@username]
      printf "No saved credential for #{@username}, create one? [yes]: "
      if @util.check_affirmative
        credential = generate_credential_entry
        @yaml['credentials'][@username] = credential
        save_config
        load_config
      end
    end

    unless @password
      @password = @util.decrypt(@yaml['credentials'][@username]['password'])
      @util.dbg("password - #{@password}")
    end

    unless @pkey_password
      @pkey_password = @util.decrypt(@yaml['credentials'][@username]['pkey_password'])
      @util.dbg("pkey_password - #{@pkey_password}")
    end

    @sudo_password = @util.decrypt(@yaml['credentials'][@username]['sudo_password'])
    @util.dbg("sudo_password - #{@sudo_password}")

  else
    @util.dbg('credential disabled')
    unless @password
      printf "Enter System Password: "
      @password = STDIN.noecho(&:gets).chomp
      puts "\n"
    end

    unless ssh_agent_loaded?
      unless @pkey_password
        puts "ssh-agent is not in use, falling back to manual entry"
        printf "Enter Private Key Password: "
        @pkey_password = STDIN.noecho(&:gets).chomp
        puts "\n"
      end
    end
  end
end
save_config() click to toggle source
# File lib/credential.rb, line 186
def save_config
  @util.dbg("saving config to '#{@config_file_path}'")
  File.open(@config_file_path, 'w') { |f| f.write @yaml.to_yaml }
end
set_password(password) click to toggle source
# File lib/credential.rb, line 90
def set_password(password)
  if password == ""
    printf "Enter System Password: "
    password = STDIN.noecho(&:gets).chomp
    password
  else
    password
  end
end
set_secure_permissions() click to toggle source
# File lib/credential.rb, line 197
def set_secure_permissions
  %x{chown #{@username} #{@config_file_path}; chmod 600 #{@config_file_path} }
  target_uid = %x{id}.split[0].match('\d+').to_s
  target_mode = '600'
  file_uid = File.stat(@config_file_path).uid.to_s
  file_mode = File.stat(@config_file_path).mode.to_s(8)[-3..-1]
  @util.dbg("target_uid: #{target_uid}, target_mode: #{target_mode}")
  @util.dbg("file_uid:   #{file_uid},   file_mode:   #{file_mode}")
  unless target_uid == file_uid && target_mode == file_mode 
    raise "Failed to set permissions on #{@config_file_path}".red
  end
end
set_username(username) click to toggle source
# File lib/credential.rb, line 82
def set_username(username)
  unless username.nil? or username == ''
    @username = username
  else
    @username = %x{whoami}.chomp.to_s
  end
end
ssh_agent_loaded?() click to toggle source
# File lib/credential.rb, line 143
def ssh_agent_loaded?
  begin
    @util.dbg('ssh-agent begin check')
    Net::SSH::Authentication::Agent.new.connect!
    @util.dbg('ssh-agent loaded')
    true
  rescue Net::SSH::Authentication::AgentNotAvailable
    @util.dbg('ssh-agent not loaded')
    false
  end
end