Add tests for new hook

This commit is contained in:
sophia 2020-08-20 15:55:39 -05:00
parent 0d1635303f
commit fffc555faf
5 changed files with 190 additions and 11 deletions

View File

@ -29,7 +29,7 @@ module Vagrant
"vagrantup.com".freeze
].freeze
attr_reader :source
attr_accessor :source
attr_reader :destination
attr_accessor :headers

View File

@ -6,6 +6,9 @@ require_relative "./add_authentication"
require Vagrant.source_root.join("plugins/commands/cloud/client/client")
# Similar to AddAuthentication this middleware will add authentication for interacting
# with Vagrant cloud. It does this by adding Authentication headers to a
# Vagrant::Util::Downloader object.
module VagrantPlugins
module CloudCommand
class AddDownloaderAuthentication < AddAuthentication
@ -13,16 +16,16 @@ module VagrantPlugins
def call(env)
client = Client.new(env[:env])
token = client.token
target_url = URI.parse(env[:downloader].source)
Vagrant::Util::CredentialScrubber.sensitive(token)
if target_url.host != TARGET_HOST && REPLACEMENT_HOSTS.include?(target_url.host)
begin
target_url.host = TARGET_HOST
target_url = target_url.to_s
rescue URI::Error
# if there is an error, use current target_url
begin
target_url = URI.parse(env[:downloader].source)
if target_url.host != TARGET_HOST && REPLACEMENT_HOSTS.include?(target_url.host)
target_url.host = TARGET_HOST
env[:downloader].source = target_url.to_s
end
rescue URI::Error
# if there is an error, use current target_url
end
server_uri = URI.parse(Vagrant.server_url.to_s)
@ -35,7 +38,8 @@ module VagrantPlugins
self.class.custom_host_notified!
end
if env[:downloader].headers && !env[:downloader].headers.any? { |h| h.include?("Authorization") }
if !Array(env[:downloader].headers).any? { |h| h.include?("Authorization") }
env[:downloader].headers ||= []
env[:downloader].headers << "Authorization: Bearer #{token}"
end
end

View File

@ -0,0 +1,155 @@
require File.expand_path("../../../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/cloud/auth/middleware/add_downloader_authentication")
require "vagrant/util/downloader"
describe VagrantPlugins::CloudCommand::AddDownloaderAuthentication do
include_context "unit"
let(:app) { lambda { |env| } }
let(:ui) { double("ui") }
let(:env) { {
env: iso_env,
ui: ui
} }
let(:iso_env) { isolated_environment.create_vagrant_env }
let(:server_url) { "http://vagrantcloud.com/box.box" }
let(:dwnloader) { Vagrant::Util::Downloader.new(server_url, "/some/path", {}) }
subject { described_class.new(app, env) }
before do
allow(Vagrant).to receive(:server_url).and_return(server_url)
allow(ui).to receive(:warn)
stub_env("ATLAS_TOKEN" => nil)
end
describe "#call" do
context "non full paths" do
let(:server_url) { "http://vagrantcloud.com" }
let(:dwnloader) { Vagrant::Util::Downloader.new(server_url, "/some/path", {}) }
it "does nothing if we have no server set" do
allow(Vagrant).to receive(:server_url).and_return(nil)
VagrantPlugins::CloudCommand::Client.new(iso_env).store_token("fooboohoo")
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers.nil?).to eq(true)
end
it "does nothing if we aren't logged in" do
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers.nil?).to eq(true)
end
end
context "custom server" do
let(:server_url) { "http://surprise.com/box.box" }
let(:dwnloader) { Vagrant::Util::Downloader.new(server_url, "/some/path", {}) }
it "warns when adding token to custom server" do
server_url = "https://surprise.com"
allow(Vagrant).to receive(:server_url).and_return(server_url)
token = "foobarbaz"
VagrantPlugins::CloudCommand::Client.new(iso_env).store_token(token)
expect(subject).to receive(:sleep).once
expect(ui).to receive(:warn).once
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers).to eq(["Authorization: Bearer #{token}"])
end
end
context "replacement hosts" do
let(:dwnloader) { Vagrant::Util::Downloader.new("https://app.vagrantup.com", "/some/path", {}) }
it "modifies host URL to target if authorized host" do
token = "foobarbaz"
VagrantPlugins::CloudCommand::Client.new(iso_env).store_token(token)
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers).to eq(["Authorization: Bearer #{token}"])
expect(URI.parse(env[:downloader].source).host).to eq(VagrantPlugins::CloudCommand::AddDownloaderAuthentication::TARGET_HOST)
end
end
context "malformed url" do
let(:bad_url) { "this is not a valid url" }
let(:dwnloader) { Vagrant::Util::Downloader.new(bad_url, "/some/path", {}) }
it "ignores urls that it cannot parse" do
# Ensure the bad URL does cause an exception
expect{ URI.parse(bad_url) }.to raise_error URI::Error
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].source).to eq(bad_url)
end
end
context "with an headers already added" do
let(:auth_header) { "Authorization Bearer: token" }
let(:other_header) {"some: thing"}
let(:dwnloader) { Vagrant::Util::Downloader.new(server_url, "/some/path", {headers: [other_header]}) }
it "appends the auth header" do
token = "foobarbaz"
VagrantPlugins::CloudCommand::Client.new(iso_env).store_token(token)
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers).to eq([other_header, "Authorization: Bearer #{token}"])
end
context "with local file path" do
let(:file_path) { "file:////path/to/box.box" }
let(:dwnloader) { Vagrant::Util::Downloader.new(file_path, "/some/path", {}) }
it "returns original urls when not modified" do
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].source).to eq(file_path)
expect(env[:downloader].headers).to eq(nil)
end
end
it "does not append multiple access_tokens" do
dwnloader.headers << auth_header
token = "foobarbaz"
VagrantPlugins::CloudCommand::Client.new(iso_env).store_token(token)
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers).to eq([other_header, auth_header])
end
end
it "adds a token to the headers" do
token = "foobarbaz"
VagrantPlugins::CloudCommand::Client.new(iso_env).store_token(token)
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers).to eq(["Authorization: Bearer #{token}"])
end
it "does not append the access token to vagrantcloud.com URLs if Atlas" do
server_url = "https://atlas.hashicorp.com"
allow(Vagrant).to receive(:server_url).and_return(server_url)
allow(subject).to receive(:sleep)
token = "foobarbaz"
VagrantPlugins::CloudCommand::Client.new(iso_env).store_token(token)
env[:downloader] = dwnloader
subject.call(env)
expect(env[:downloader].headers).to eq(nil)
end
end
end

View File

@ -595,8 +595,10 @@ describe Vagrant::Action::Builtin::BoxAdd, :skip_windows, :bsdtar do
env[:box_url] = "foo"
env[:hook] = double("hook")
allow(env[:hook]).to receive(:call) do |name, opts|
expect(name).to eq(:authenticate_box_url)
expect(env[:hook]).to receive(:call).with(:authenticate_box_downloader, any_args).at_least(:once)
allow(env[:hook]).to receive(:call).with(:authenticate_box_url, any_args).at_least(:once) do |name, opts|
if opts[:box_urls] == ["foo"]
next { box_urls: [real_url] }
elsif opts[:box_urls] == ["bar"]

View File

@ -285,6 +285,24 @@ describe Vagrant::Box, :skip_windows do
expect { subject.load_metadata }.
to raise_error(Vagrant::Errors::BoxMetadataDownloadError)
end
context "box has a hook for adding authentication" do
let(:hook){ double("hook") }
subject do
described_class.new(
name, provider, version, directory,
metadata_url: metadata_url.path, hook: hook)
end
it "add authentication headers to the url" do
expect(hook).to receive(:call).with(:authenticate_box_downloader, any_args)
result = subject.load_metadata
expect(result.name).to eq("foo")
expect(result.description).to eq("bar")
end
end
end
describe "destroying" do