Remove all unused code related to the deprecated login command
This commit is contained in:
parent
70d36bc7cd
commit
baa24af179
@ -1,4 +1,3 @@
|
|||||||
require "rest_client"
|
|
||||||
require "vagrant_cloud"
|
require "vagrant_cloud"
|
||||||
require "vagrant/util/downloader"
|
require "vagrant/util/downloader"
|
||||||
require "vagrant/util/presence"
|
require "vagrant/util/presence"
|
||||||
|
|||||||
@ -1,253 +0,0 @@
|
|||||||
require "rest_client"
|
|
||||||
require "vagrant/util/downloader"
|
|
||||||
require "vagrant/util/presence"
|
|
||||||
|
|
||||||
module VagrantPlugins
|
|
||||||
module LoginCommand
|
|
||||||
class Client
|
|
||||||
APP = "app".freeze
|
|
||||||
|
|
||||||
include Vagrant::Util::Presence
|
|
||||||
|
|
||||||
attr_accessor :username_or_email
|
|
||||||
attr_accessor :password
|
|
||||||
attr_reader :two_factor_default_delivery_method
|
|
||||||
attr_reader :two_factor_delivery_methods
|
|
||||||
|
|
||||||
# Initializes a login client with the given Vagrant::Environment.
|
|
||||||
#
|
|
||||||
# @param [Vagrant::Environment] env
|
|
||||||
def initialize(env)
|
|
||||||
@logger = Log4r::Logger.new("vagrant::login::client")
|
|
||||||
@env = env
|
|
||||||
end
|
|
||||||
|
|
||||||
# Removes the token, effectively logging the user out.
|
|
||||||
def clear_token
|
|
||||||
@logger.info("Clearing token")
|
|
||||||
token_path.delete if token_path.file?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Checks if the user is logged in by verifying their authentication
|
|
||||||
# token.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
def logged_in?
|
|
||||||
token = self.token
|
|
||||||
return false if !token
|
|
||||||
|
|
||||||
with_error_handling do
|
|
||||||
url = "#{Vagrant.server_url}/api/v1/authenticate" +
|
|
||||||
"?access_token=#{token}"
|
|
||||||
RestClient.get(url, content_type: :json)
|
|
||||||
true
|
|
||||||
end
|
|
||||||
rescue Errors::Unauthorized
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Login logs a user in and returns the token for that user. The token
|
|
||||||
# is _not_ stored unless {#store_token} is called.
|
|
||||||
#
|
|
||||||
# @param [String] description
|
|
||||||
# @param [String] code
|
|
||||||
# @return [String] token The access token, or nil if auth failed.
|
|
||||||
def login(description: nil, code: nil)
|
|
||||||
@logger.info("Logging in '#{username_or_email}'")
|
|
||||||
|
|
||||||
response = post(
|
|
||||||
"/api/v1/authenticate", {
|
|
||||||
user: {
|
|
||||||
login: username_or_email,
|
|
||||||
password: password
|
|
||||||
},
|
|
||||||
token: {
|
|
||||||
description: description
|
|
||||||
},
|
|
||||||
two_factor: {
|
|
||||||
code: code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
response["token"]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Requests a 2FA code
|
|
||||||
# @param [String] delivery_method
|
|
||||||
def request_code(delivery_method)
|
|
||||||
@env.ui.warn("Requesting 2FA code via #{delivery_method.upcase}...")
|
|
||||||
|
|
||||||
response = post(
|
|
||||||
"/api/v1/two-factor/request-code", {
|
|
||||||
user: {
|
|
||||||
login: username_or_email,
|
|
||||||
password: password
|
|
||||||
},
|
|
||||||
two_factor: {
|
|
||||||
delivery_method: delivery_method.downcase
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
two_factor = response['two_factor']
|
|
||||||
obfuscated_destination = two_factor['obfuscated_destination']
|
|
||||||
|
|
||||||
@env.ui.success("2FA code sent to #{obfuscated_destination}.")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Issues a post to a Vagrant Cloud path with the given payload.
|
|
||||||
# @param [String] path
|
|
||||||
# @param [Hash] payload
|
|
||||||
# @return [Hash] response data
|
|
||||||
def post(path, payload)
|
|
||||||
with_error_handling do
|
|
||||||
url = File.join(Vagrant.server_url, path)
|
|
||||||
|
|
||||||
proxy = nil
|
|
||||||
proxy ||= ENV["HTTPS_PROXY"] || ENV["https_proxy"]
|
|
||||||
proxy ||= ENV["HTTP_PROXY"] || ENV["http_proxy"]
|
|
||||||
RestClient.proxy = proxy
|
|
||||||
|
|
||||||
response = RestClient::Request.execute(
|
|
||||||
method: :post,
|
|
||||||
url: url,
|
|
||||||
payload: JSON.dump(payload),
|
|
||||||
proxy: proxy,
|
|
||||||
headers: {
|
|
||||||
accept: :json,
|
|
||||||
content_type: :json,
|
|
||||||
user_agent: Vagrant::Util::Downloader::USER_AGENT,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
JSON.load(response.to_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Stores the given token locally, removing any previous tokens.
|
|
||||||
#
|
|
||||||
# @param [String] token
|
|
||||||
def store_token(token)
|
|
||||||
@logger.info("Storing token in #{token_path}")
|
|
||||||
|
|
||||||
token_path.open("w") do |f|
|
|
||||||
f.write(token)
|
|
||||||
end
|
|
||||||
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reads the access token if there is one. This will first read the
|
|
||||||
# `VAGRANT_CLOUD_TOKEN` environment variable and then fallback to the stored
|
|
||||||
# access token on disk.
|
|
||||||
#
|
|
||||||
# @return [String]
|
|
||||||
def token
|
|
||||||
if present?(ENV["VAGRANT_CLOUD_TOKEN"]) && token_path.exist?
|
|
||||||
@env.ui.warn <<-EOH.strip
|
|
||||||
Vagrant detected both the VAGRANT_CLOUD_TOKEN environment variable and a Vagrant login
|
|
||||||
token are present on this system. The VAGRANT_CLOUD_TOKEN environment variable takes
|
|
||||||
precedence over the locally stored token. To remove this error, either unset
|
|
||||||
the VAGRANT_CLOUD_TOKEN environment variable or remove the login token stored on disk:
|
|
||||||
|
|
||||||
~/.vagrant.d/data/vagrant_login_token
|
|
||||||
|
|
||||||
EOH
|
|
||||||
end
|
|
||||||
|
|
||||||
if present?(ENV["VAGRANT_CLOUD_TOKEN"])
|
|
||||||
@logger.debug("Using authentication token from environment variable")
|
|
||||||
return ENV["VAGRANT_CLOUD_TOKEN"]
|
|
||||||
end
|
|
||||||
|
|
||||||
if token_path.exist?
|
|
||||||
@logger.debug("Using authentication token from disk at #{token_path}")
|
|
||||||
return token_path.read.strip
|
|
||||||
end
|
|
||||||
|
|
||||||
if present?(ENV["ATLAS_TOKEN"])
|
|
||||||
@logger.warn("ATLAS_TOKEN detected within environment. Using ATLAS_TOKEN in place of VAGRANT_CLOUD_TOKEN.")
|
|
||||||
return ENV["ATLAS_TOKEN"]
|
|
||||||
end
|
|
||||||
|
|
||||||
@logger.debug("No authentication token in environment or #{token_path}")
|
|
||||||
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def with_error_handling(&block)
|
|
||||||
yield
|
|
||||||
rescue RestClient::Unauthorized
|
|
||||||
@logger.debug("Unauthorized!")
|
|
||||||
raise Errors::Unauthorized
|
|
||||||
rescue RestClient::BadRequest => e
|
|
||||||
@logger.debug("Bad request:")
|
|
||||||
@logger.debug(e.message)
|
|
||||||
@logger.debug(e.backtrace.join("\n"))
|
|
||||||
parsed_response = JSON.parse(e.response)
|
|
||||||
errors = parsed_response["errors"].join("\n")
|
|
||||||
raise Errors::ServerError, errors: errors
|
|
||||||
rescue RestClient::NotAcceptable => e
|
|
||||||
@logger.debug("Got unacceptable response:")
|
|
||||||
@logger.debug(e.message)
|
|
||||||
@logger.debug(e.backtrace.join("\n"))
|
|
||||||
|
|
||||||
parsed_response = JSON.parse(e.response)
|
|
||||||
|
|
||||||
if two_factor = parsed_response['two_factor']
|
|
||||||
store_two_factor_information two_factor
|
|
||||||
|
|
||||||
if two_factor_default_delivery_method != APP
|
|
||||||
request_code two_factor_default_delivery_method
|
|
||||||
end
|
|
||||||
|
|
||||||
raise Errors::TwoFactorRequired
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
errors = parsed_response["errors"].join("\n")
|
|
||||||
raise Errors::ServerError, errors: errors
|
|
||||||
rescue JSON::ParserError; end
|
|
||||||
|
|
||||||
raise "An unexpected error occurred: #{e.inspect}"
|
|
||||||
rescue SocketError
|
|
||||||
@logger.info("Socket error")
|
|
||||||
raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def token_path
|
|
||||||
@env.data_dir.join("vagrant_login_token")
|
|
||||||
end
|
|
||||||
|
|
||||||
def store_two_factor_information(two_factor)
|
|
||||||
@two_factor_default_delivery_method =
|
|
||||||
two_factor['default_delivery_method']
|
|
||||||
|
|
||||||
@two_factor_delivery_methods =
|
|
||||||
two_factor['delivery_methods']
|
|
||||||
|
|
||||||
@env.ui.warn "2FA is enabled for your account."
|
|
||||||
if two_factor_default_delivery_method == APP
|
|
||||||
@env.ui.info "Enter the code from your authenticator."
|
|
||||||
else
|
|
||||||
@env.ui.info "Default method is " \
|
|
||||||
"'#{two_factor_default_delivery_method}'."
|
|
||||||
end
|
|
||||||
|
|
||||||
other_delivery_methods =
|
|
||||||
two_factor_delivery_methods - [APP]
|
|
||||||
|
|
||||||
if other_delivery_methods.any?
|
|
||||||
other_delivery_methods_sentence = other_delivery_methods
|
|
||||||
.map { |word| "'#{word}'" }
|
|
||||||
.join(' or ')
|
|
||||||
@env.ui.info "You can also type #{other_delivery_methods_sentence} " \
|
|
||||||
"to request a new code."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
require 'socket'
|
|
||||||
|
|
||||||
module VagrantPlugins
|
|
||||||
module LoginCommand
|
|
||||||
class Command < Vagrant.plugin("2", "command")
|
|
||||||
def self.synopsis
|
|
||||||
"log in to HashiCorp's Vagrant Cloud"
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute
|
|
||||||
options = {}
|
|
||||||
|
|
||||||
opts = OptionParser.new do |o|
|
|
||||||
o.banner = "Usage: vagrant login"
|
|
||||||
o.separator ""
|
|
||||||
o.on("-c", "--check", "Only checks if you're logged in") do |c|
|
|
||||||
options[:check] = c
|
|
||||||
end
|
|
||||||
|
|
||||||
o.on("-d", "--description DESCRIPTION", String, "Description for the Vagrant Cloud token") do |t|
|
|
||||||
options[:description] = t
|
|
||||||
end
|
|
||||||
|
|
||||||
o.on("-k", "--logout", "Logs you out if you're logged in") do |k|
|
|
||||||
options[:logout] = k
|
|
||||||
end
|
|
||||||
|
|
||||||
o.on("-t", "--token TOKEN", String, "Set the Vagrant Cloud token") do |t|
|
|
||||||
options[:token] = t
|
|
||||||
end
|
|
||||||
|
|
||||||
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Specify your Vagrant Cloud username or email address") do |t|
|
|
||||||
options[:login] = t
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse the options
|
|
||||||
argv = parse_options(opts)
|
|
||||||
return if !argv
|
|
||||||
|
|
||||||
@client = Client.new(@env)
|
|
||||||
@client.username_or_email = options[:login]
|
|
||||||
|
|
||||||
# Determine what task we're actually taking based on flags
|
|
||||||
if options[:check]
|
|
||||||
return execute_check
|
|
||||||
elsif options[:logout]
|
|
||||||
return execute_logout
|
|
||||||
elsif options[:token]
|
|
||||||
return execute_token(options[:token])
|
|
||||||
end
|
|
||||||
|
|
||||||
# Let the user know what is going on.
|
|
||||||
@env.ui.output(I18n.t("login_command.command_header") + "\n")
|
|
||||||
|
|
||||||
# If it is a private cloud installation, show that
|
|
||||||
if Vagrant.server_url != Vagrant::DEFAULT_SERVER_URL
|
|
||||||
@env.ui.output("Vagrant Cloud URL: #{Vagrant.server_url}")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Ask for the username
|
|
||||||
if @client.username_or_email
|
|
||||||
@env.ui.output("Vagrant Cloud username or email: #{@client.username_or_email}")
|
|
||||||
end
|
|
||||||
until @client.username_or_email
|
|
||||||
@client.username_or_email = @env.ui.ask("Vagrant Cloud username or email: ")
|
|
||||||
end
|
|
||||||
|
|
||||||
until @client.password
|
|
||||||
@client.password = @env.ui.ask("Password (will be hidden): ", echo: false)
|
|
||||||
end
|
|
||||||
|
|
||||||
description = options[:description]
|
|
||||||
if description
|
|
||||||
@env.ui.output("Token description: #{description}")
|
|
||||||
else
|
|
||||||
description_default = "Vagrant login from #{Socket.gethostname}"
|
|
||||||
until description
|
|
||||||
description =
|
|
||||||
@env.ui.ask("Token description (Defaults to #{description_default.inspect}): ")
|
|
||||||
end
|
|
||||||
description = description_default if description.empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
code = nil
|
|
||||||
|
|
||||||
begin
|
|
||||||
token = @client.login(description: description, code: code)
|
|
||||||
rescue Errors::TwoFactorRequired
|
|
||||||
until code
|
|
||||||
code = @env.ui.ask("2FA code: ")
|
|
||||||
|
|
||||||
if @client.two_factor_delivery_methods.include?(code.downcase)
|
|
||||||
delivery_method, code = code, nil
|
|
||||||
@client.request_code delivery_method
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
retry
|
|
||||||
end
|
|
||||||
|
|
||||||
@client.store_token(token)
|
|
||||||
@env.ui.success(I18n.t("login_command.logged_in"))
|
|
||||||
0
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_check
|
|
||||||
if @client.logged_in?
|
|
||||||
@env.ui.success(I18n.t("login_command.check_logged_in"))
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
@env.ui.error(I18n.t("login_command.check_not_logged_in"))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_logout
|
|
||||||
@client.clear_token
|
|
||||||
@env.ui.success(I18n.t("login_command.logged_out"))
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_token(token)
|
|
||||||
@client.store_token(token)
|
|
||||||
@env.ui.success(I18n.t("login_command.token_saved"))
|
|
||||||
|
|
||||||
if @client.logged_in?
|
|
||||||
@env.ui.success(I18n.t("login_command.check_logged_in"))
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
@env.ui.error(I18n.t("login_command.invalid_token"))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
module VagrantPlugins
|
|
||||||
module LoginCommand
|
|
||||||
module Errors
|
|
||||||
class Error < Vagrant::Errors::VagrantError
|
|
||||||
error_namespace("login_command.errors")
|
|
||||||
end
|
|
||||||
|
|
||||||
class ServerError < Error
|
|
||||||
error_key(:server_error)
|
|
||||||
end
|
|
||||||
|
|
||||||
class ServerUnreachable < Error
|
|
||||||
error_key(:server_unreachable)
|
|
||||||
end
|
|
||||||
|
|
||||||
class Unauthorized < Error
|
|
||||||
error_key(:unauthorized)
|
|
||||||
end
|
|
||||||
|
|
||||||
class TwoFactorRequired < Error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
en:
|
|
||||||
login_command:
|
|
||||||
middleware:
|
|
||||||
authentication:
|
|
||||||
different_target: |-
|
|
||||||
Vagrant has detected a custom Vagrant server in use for downloading
|
|
||||||
box files. An authentication token is currently set which will be
|
|
||||||
added to the box request. If the custom Vagrant server should not
|
|
||||||
be receiving the authentication token, please unset it.
|
|
||||||
|
|
||||||
Known Vagrant server: %{known_host}
|
|
||||||
Custom Vagrant server: %{custom_host}
|
|
||||||
|
|
||||||
Press ctrl-c to cancel...
|
|
||||||
errors:
|
|
||||||
server_error: |-
|
|
||||||
The Vagrant Cloud server responded with a not-OK response:
|
|
||||||
|
|
||||||
%{errors}
|
|
||||||
server_unreachable: |-
|
|
||||||
The Vagrant Cloud server is not currently accepting connections. Please check
|
|
||||||
your network connection and try again later.
|
|
||||||
|
|
||||||
unauthorized: |-
|
|
||||||
Invalid username or password. Please try again.
|
|
||||||
|
|
||||||
check_logged_in: |-
|
|
||||||
You are already logged in.
|
|
||||||
check_not_logged_in: |-
|
|
||||||
You are not currently logged in. Please run `vagrant login` and provide
|
|
||||||
your login information to authenticate.
|
|
||||||
command_header: |-
|
|
||||||
In a moment we will ask for your username and password to HashiCorp's
|
|
||||||
Vagrant Cloud. After authenticating, we will store an access token locally on
|
|
||||||
disk. Your login details will be transmitted over a secure connection, and
|
|
||||||
are never stored on disk locally.
|
|
||||||
|
|
||||||
If you do not have an Vagrant Cloud account, sign up at
|
|
||||||
https://www.vagrantcloud.com
|
|
||||||
invalid_login: |-
|
|
||||||
Invalid username or password. Please try again.
|
|
||||||
invalid_token: |-
|
|
||||||
Invalid token. Please try again.
|
|
||||||
logged_in: |-
|
|
||||||
You are now logged in.
|
|
||||||
logged_out: |-
|
|
||||||
You are logged out.
|
|
||||||
token_saved: |-
|
|
||||||
The token was successfully saved.
|
|
||||||
@ -2,9 +2,6 @@ require "vagrant"
|
|||||||
|
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
module LoginCommand
|
module LoginCommand
|
||||||
autoload :Client, File.expand_path("../client", __FILE__)
|
|
||||||
autoload :Errors, File.expand_path("../errors", __FILE__)
|
|
||||||
|
|
||||||
class Plugin < Vagrant.plugin("2")
|
class Plugin < Vagrant.plugin("2")
|
||||||
name "vagrant-login"
|
name "vagrant-login"
|
||||||
description <<-DESC
|
description <<-DESC
|
||||||
@ -13,18 +10,8 @@ module VagrantPlugins
|
|||||||
|
|
||||||
command(:login) do
|
command(:login) do
|
||||||
require File.expand_path("../../cloud/auth/login", __FILE__)
|
require File.expand_path("../../cloud/auth/login", __FILE__)
|
||||||
init!
|
|
||||||
VagrantPlugins::CloudCommand::AuthCommand::Command::Login
|
VagrantPlugins::CloudCommand::AuthCommand::Command::Login
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def self.init!
|
|
||||||
return if defined?(@_init)
|
|
||||||
I18n.load_path << File.expand_path("../../cloud/locales/en.yml", __FILE__)
|
|
||||||
I18n.reload!
|
|
||||||
@_init = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,261 +0,0 @@
|
|||||||
require File.expand_path("../../../../base", __FILE__)
|
|
||||||
|
|
||||||
require Vagrant.source_root.join("plugins/commands/login/command")
|
|
||||||
|
|
||||||
describe VagrantPlugins::LoginCommand::Client do
|
|
||||||
include_context "unit"
|
|
||||||
|
|
||||||
let(:env) { isolated_environment.create_vagrant_env }
|
|
||||||
|
|
||||||
subject(:client) { described_class.new(env) }
|
|
||||||
|
|
||||||
before(:all) do
|
|
||||||
I18n.load_path << Vagrant.source_root.join("plugins/commands/login/locales/en.yml")
|
|
||||||
I18n.reload!
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
|
||||||
stub_env("ATLAS_TOKEN" => nil)
|
|
||||||
subject.clear_token
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#logged_in?" do
|
|
||||||
let(:url) { "#{Vagrant.server_url}/api/v1/authenticate?access_token=#{token}" }
|
|
||||||
let(:headers) { { "Content-Type" => "application/json" } }
|
|
||||||
|
|
||||||
before { allow(subject).to receive(:token).and_return(token) }
|
|
||||||
|
|
||||||
context "when there is no token" do
|
|
||||||
let(:token) { nil }
|
|
||||||
|
|
||||||
it "returns false" do
|
|
||||||
expect(subject.logged_in?).to be(false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when there is a token" do
|
|
||||||
let(:token) { "ABCD1234" }
|
|
||||||
|
|
||||||
it "returns true if the endpoint returns a 200" do
|
|
||||||
stub_request(:get, url)
|
|
||||||
.with(headers: headers)
|
|
||||||
.to_return(body: JSON.pretty_generate("token" => token))
|
|
||||||
expect(subject.logged_in?).to be(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an error if the endpoint returns a non-200" do
|
|
||||||
stub_request(:get, url)
|
|
||||||
.with(headers: headers)
|
|
||||||
.to_return(body: JSON.pretty_generate("bad" => true), status: 401)
|
|
||||||
expect(subject.logged_in?).to be(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an exception if the server cannot be found" do
|
|
||||||
stub_request(:get, url)
|
|
||||||
.to_raise(SocketError)
|
|
||||||
expect { subject.logged_in? }
|
|
||||||
.to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#login" do
|
|
||||||
let(:request) {
|
|
||||||
{
|
|
||||||
user: {
|
|
||||||
login: login,
|
|
||||||
password: password,
|
|
||||||
},
|
|
||||||
token: {
|
|
||||||
description: description,
|
|
||||||
},
|
|
||||||
two_factor: {
|
|
||||||
code: nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:login) { "foo" }
|
|
||||||
let(:password) { "bar" }
|
|
||||||
let(:description) { "Token description" }
|
|
||||||
|
|
||||||
let(:headers) {
|
|
||||||
{
|
|
||||||
"Accept" => "application/json",
|
|
||||||
"Content-Type" => "application/json",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let(:response) {
|
|
||||||
{
|
|
||||||
token: "baz"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
it "returns the access token after successful login" do
|
|
||||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
|
||||||
with(body: JSON.dump(request), headers: headers).
|
|
||||||
to_return(status: 200, body: JSON.dump(response))
|
|
||||||
|
|
||||||
client.username_or_email = login
|
|
||||||
client.password = password
|
|
||||||
|
|
||||||
expect(client.login(description: "Token description")).to eq("baz")
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when 2fa is required" do
|
|
||||||
let(:response) {
|
|
||||||
{
|
|
||||||
two_factor: {
|
|
||||||
default_delivery_method: default_delivery_method,
|
|
||||||
delivery_methods: delivery_methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let(:default_delivery_method) { "app" }
|
|
||||||
let(:delivery_methods) { ["app"] }
|
|
||||||
|
|
||||||
before do
|
|
||||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
|
||||||
to_return(status: 406, body: JSON.dump(response))
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises a two-factor required error" do
|
|
||||||
expect {
|
|
||||||
client.login
|
|
||||||
}.to raise_error(VagrantPlugins::LoginCommand::Errors::TwoFactorRequired)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when the default delivery method is not app" do
|
|
||||||
let(:default_delivery_method) { "sms" }
|
|
||||||
let(:delivery_methods) { ["app", "sms"] }
|
|
||||||
|
|
||||||
it "requests a code and then raises a two-factor required error" do
|
|
||||||
expect(client)
|
|
||||||
.to receive(:request_code)
|
|
||||||
.with(default_delivery_method)
|
|
||||||
|
|
||||||
expect {
|
|
||||||
client.login
|
|
||||||
}.to raise_error(VagrantPlugins::LoginCommand::Errors::TwoFactorRequired)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "on bad login" do
|
|
||||||
before do
|
|
||||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
|
||||||
to_return(status: 401, body: "")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an error" do
|
|
||||||
expect {
|
|
||||||
client.login
|
|
||||||
}.to raise_error(VagrantPlugins::LoginCommand::Errors::Unauthorized)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "if it can't reach the server" do
|
|
||||||
before do
|
|
||||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
|
||||||
to_raise(SocketError)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raises an exception" do
|
|
||||||
expect {
|
|
||||||
subject.login
|
|
||||||
}.to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#request_code" do
|
|
||||||
let(:request) {
|
|
||||||
{
|
|
||||||
user: {
|
|
||||||
login: login,
|
|
||||||
password: password,
|
|
||||||
},
|
|
||||||
two_factor: {
|
|
||||||
delivery_method: delivery_method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:login) { "foo" }
|
|
||||||
let(:password) { "bar" }
|
|
||||||
let(:delivery_method) { "sms" }
|
|
||||||
|
|
||||||
let(:headers) {
|
|
||||||
{
|
|
||||||
"Accept" => "application/json",
|
|
||||||
"Content-Type" => "application/json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:response) {
|
|
||||||
{
|
|
||||||
two_factor: {
|
|
||||||
obfuscated_destination: "SMS number ending in 1234"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
it "displays that the code was sent" do
|
|
||||||
expect(env.ui)
|
|
||||||
.to receive(:success)
|
|
||||||
.with("2FA code sent to SMS number ending in 1234.")
|
|
||||||
|
|
||||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/two-factor/request-code").
|
|
||||||
with(body: JSON.dump(request), headers: headers).
|
|
||||||
to_return(status: 201, body: JSON.dump(response))
|
|
||||||
|
|
||||||
client.username_or_email = login
|
|
||||||
client.password = password
|
|
||||||
|
|
||||||
client.request_code delivery_method
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#token" do
|
|
||||||
it "reads ATLAS_TOKEN" do
|
|
||||||
stub_env("ATLAS_TOKEN" => "ABCD1234")
|
|
||||||
expect(subject.token).to eq("ABCD1234")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "reads the stored file" do
|
|
||||||
subject.store_token("EFGH5678")
|
|
||||||
expect(subject.token).to eq("EFGH5678")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prefers the environment variable" do
|
|
||||||
stub_env("VAGRANT_CLOUD_TOKEN" => "ABCD1234")
|
|
||||||
subject.store_token("EFGH5678")
|
|
||||||
expect(subject.token).to eq("ABCD1234")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prints a warning if the envvar and stored file are both present" do
|
|
||||||
stub_env("VAGRANT_CLOUD_TOKEN" => "ABCD1234")
|
|
||||||
subject.store_token("EFGH5678")
|
|
||||||
expect(env.ui).to receive(:warn).with(/detected both/)
|
|
||||||
subject.token
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns nil if there's no token set" do
|
|
||||||
expect(subject.token).to be(nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#store_token, #clear_token" do
|
|
||||||
it "stores the token and can re-access it" do
|
|
||||||
subject.store_token("foo")
|
|
||||||
expect(subject.token).to eq("foo")
|
|
||||||
expect(described_class.new(env).token).to eq("foo")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "deletes the token" do
|
|
||||||
subject.store_token("foo")
|
|
||||||
subject.clear_token
|
|
||||||
expect(subject.token).to be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
require File.expand_path("../../../../base", __FILE__)
|
|
||||||
|
|
||||||
require Vagrant.source_root.join("plugins/commands/login/command")
|
|
||||||
|
|
||||||
describe VagrantPlugins::LoginCommand::Command do
|
|
||||||
include_context "unit"
|
|
||||||
|
|
||||||
let(:env) { isolated_environment.create_vagrant_env }
|
|
||||||
|
|
||||||
let(:token_path) { env.data_dir.join("vagrant_login_token") }
|
|
||||||
|
|
||||||
let(:stdout) { StringIO.new }
|
|
||||||
let(:stderr) { StringIO.new }
|
|
||||||
|
|
||||||
subject { described_class.new(argv, env) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
stub_env("ATLAS_TOKEN" => "")
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#execute" do
|
|
||||||
context "with no args" do
|
|
||||||
let(:argv) { [] }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with --check" do
|
|
||||||
let(:argv) { ["--check"] }
|
|
||||||
|
|
||||||
context "when there is a token" do
|
|
||||||
before do
|
|
||||||
stub_request(:get, %r{^#{Vagrant.server_url}/api/v1/authenticate})
|
|
||||||
.to_return(status: 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
|
||||||
File.open(token_path, "w+") { |f| f.write("abcd1234") }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 0" do
|
|
||||||
expect(subject.execute).to eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when there is no token" do
|
|
||||||
it "returns 1" do
|
|
||||||
expect(subject.execute).to eq(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with --logout" do
|
|
||||||
let(:argv) { ["--logout"] }
|
|
||||||
|
|
||||||
it "returns 0" do
|
|
||||||
expect(subject.execute).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "clears the token" do
|
|
||||||
subject.execute
|
|
||||||
expect(File.exist?(token_path)).to be(false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with --token" do
|
|
||||||
let(:argv) { ["--token", "efgh5678"] }
|
|
||||||
|
|
||||||
context "when the token is valid" do
|
|
||||||
before do
|
|
||||||
stub_request(:get, %r{^#{Vagrant.server_url}/api/v1/authenticate})
|
|
||||||
.to_return(status: 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "sets the token" do
|
|
||||||
subject.execute
|
|
||||||
token = File.read(token_path).strip
|
|
||||||
expect(token).to eq("efgh5678")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 0" do
|
|
||||||
expect(subject.execute).to eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when the token is invalid" do
|
|
||||||
before do
|
|
||||||
stub_request(:get, %r{^#{Vagrant.server_url}/api/v1/authenticate})
|
|
||||||
.to_return(status: 401)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 1" do
|
|
||||||
expect(subject.execute).to eq(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Loading…
x
Reference in New Issue
Block a user