core: box URLs can be authenticated by hooking

This commit is contained in:
Mitchell Hashimoto 2014-03-01 11:38:04 +01:00
parent 45b17571ae
commit 7926f7f051
7 changed files with 171 additions and 15 deletions

View File

@ -57,8 +57,17 @@ module Vagrant
end
end
# Call the hook to transform URLs into authenticated URLs.
# In the case we don't have a plugin that does this, then it
# will just return the same URLs.
hook_env = env[:hook].call(:authenticate_box_url, box_urls: url)
authed_urls = hook_env[:box_urls]
if !authed_urls || authed_urls.length != url.length
raise "Bad box authentication hook, did not generate proper results."
end
# Test if any of our URLs point to metadata
is_metadata_results = url.map do |u|
is_metadata_results = authed_urls.map do |u|
begin
metadata_url?(u, env)
rescue Errors::DownloaderError => e
@ -86,7 +95,8 @@ module Vagrant
end
if is_metadata
add_from_metadata(url.first, env, expanded)
url = [url.first, authed_urls.first]
add_from_metadata(url, env, expanded)
else
add_direct(url, env)
end
@ -118,12 +128,28 @@ module Vagrant
end
# Adds a box given that the URL is a metadata document.
#
# @param [String | Array<String>] url The URL of the metadata for
# the box to add. If this is an array, then it must be a two-element
# array where the first element is the original URL and the second
# element is an authenticated URL.
# @param [Hash] env
# @param [Bool] expanded True if the metadata URL was expanded with
# a Vagrant Cloud server URL.
def add_from_metadata(url, env, expanded)
original_url = env[:box_url]
provider = env[:box_provider]
provider = Array(provider) if provider
version = env[:box_version]
authenticated_url = url
if url.is_a?(Array)
# We have both a normal URL and "authenticated" URL. Split
# them up.
authenticated_url = url[1]
url = url[0]
end
env[:ui].output(I18n.t(
"vagrant.box_loading_metadata",
name: Array(original_url).first))
@ -134,7 +160,8 @@ module Vagrant
metadata = nil
begin
metadata_path = download(url, env, json: true, ui: false)
metadata_path = download(
authenticated_url, env, json: true, ui: false)
File.open(metadata_path) do |f|
metadata = BoxMetadata.new(f)

View File

@ -44,6 +44,7 @@ module Vagrant
options ||= {}
@directory = directory
@hook = options[:hook]
@lock = Monitor.new
@temp_root = options[:temp_dir_root]
@logger = Log4r::Logger.new("vagrant::box_collection")
@ -289,6 +290,12 @@ module Vagrant
metadata_url_file = box_directory.join("metadata_url")
metadata_url = metadata_url_file.read if metadata_url_file.file?
if metadata_url && @hook
hook_env = @hook.call(
:authenticate_box_url, box_urls: [metadata_url])
metadata_url = hook_env[:box_urls].first
end
return Box.new(
name, provider, v.to_s, provider_dir,
metadata_url: metadata_url,

View File

@ -258,7 +258,10 @@ module Vagrant
#
# @return [BoxCollection]
def boxes
@_boxes ||= BoxCollection.new(boxes_path, temp_dir_root: tmp_path)
@_boxes ||= BoxCollection.new(
boxes_path,
hook: method(:hook),
temp_dir_root: tmp_path)
end
# Returns the {Config::Loader} that can be used to load Vagrantflies

View File

@ -41,9 +41,18 @@ describe VagrantPlugins::CommandBox::Command::Update do
end
it "doesn't update if they're up to date" do
action_runner.should_receive(:run).never
called = false
action_runner.stub(:run) do |callable, opts|
if opts[:box_provider]
called = true
end
opts
end
subject.execute
expect(called).to be_false
end
it "does update if there is an update" do
@ -69,14 +78,21 @@ describe VagrantPlugins::CommandBox::Command::Update do
RAW
end
action_runner.should_receive(:run).with do |action, opts|
action_called = false
action_runner.stub(:run) do |action, opts|
if opts[:box_provider]
action_called = true
expect(opts[:box_url]).to eq(metadata_url.to_s)
expect(opts[:box_provider]).to eq("virtualbox")
expect(opts[:box_version]).to eq("1.1")
true
end
opts
end
subject.execute
expect(action_called).to be_true
end
it "raises an error if there are multiple providers" do
@ -116,14 +132,21 @@ describe VagrantPlugins::CommandBox::Command::Update do
test_iso_env.box3("foo", "1.0", :vmware)
action_runner.should_receive(:run).with do |action, opts|
action_called = false
action_runner.stub(:run) do |action, opts|
if opts[:box_provider]
action_called = true
expect(opts[:box_url]).to eq(metadata_url.to_s)
expect(opts[:box_provider]).to eq("vmware")
expect(opts[:box_version]).to eq("1.1")
true
end
opts
end
subject.execute
expect(action_called).to be_true
end
it "raises an error if that provider doesn't exist" do

View File

@ -14,6 +14,7 @@ describe Vagrant::Action::Builtin::BoxAdd do
let(:app) { lambda { |env| } }
let(:env) { {
box_collection: box_collection,
hook: Proc.new { |name, env| env },
tmp_path: Pathname.new(Dir.mktmpdir),
ui: Vagrant::UI::Silent.new,
} }
@ -262,6 +263,60 @@ describe Vagrant::Action::Builtin::BoxAdd do
end
end
it "authenticates HTTP URLs and adds them" do
box_path = iso_env.box2_file(:virtualbox)
tf = Tempfile.new(["vagrant", ".json"]).tap do |f|
f.write(<<-RAW)
{
"name": "foo/bar",
"versions": [
{
"version": "0.5"
},
{
"version": "0.7",
"providers": [
{
"name": "virtualbox",
"url": "#{box_path}"
}
]
}
]
}
RAW
f.close
end
md_path = Pathname.new(tf.path)
with_web_server(md_path) do |port|
real_url = "http://127.0.0.1:#{port}/#{md_path.basename}"
# Set the box URL to something fake so we can modify it in place
env[:box_url] = "foo"
env[:hook] = double("hook")
env[:hook].should_receive(:call) do |name, opts|
expect(name).to eq(:authenticate_box_url)
expect(opts[:box_urls]).to eq(["foo"])
{ box_urls: [real_url] }
end
box_collection.should_receive(:add).with do |path, name, version, **opts|
expect(name).to eq("foo/bar")
expect(version).to eq("0.7")
expect(checksum(path)).to eq(checksum(box_path))
expect(opts[:metadata_url]).to eq(env[:box_url])
true
end.and_return(box)
app.should_receive(:call).with(env)
subject.call(env)
end
end
it "raises an error if no Vagrant server is set" do
tf = Tempfile.new("foo")
tf.close

View File

@ -56,6 +56,42 @@ describe Vagrant::BoxCollection do
expect(result).to_not be_nil
expect(result).to be_kind_of(box_class)
expect(result.name).to eq("foo")
expect(result.metadata_url).to be_nil
end
it "sets a metadata URL if it has one" do
# Create the "box"
environment.box3("foo", "0", :virtualbox,
metadata_url: "foourl")
# Actual test
result = subject.find("foo", :virtualbox, ">= 0")
expect(result).to_not be_nil
expect(result).to be_kind_of(box_class)
expect(result.name).to eq("foo")
expect(result.metadata_url).to eq("foourl")
end
it "sets the metadata URL to an authenticated URL if it has one" do
hook = double("hook")
subject = described_class.new(environment.boxes_dir, hook: hook)
# Create the "box"
environment.box3("foo", "0", :virtualbox,
metadata_url: "foourl")
hook.should_receive(:call).with do |name, env|
expect(name).to eq(:authenticate_box_url)
expect(env[:box_urls]).to eq(["foourl"])
true
end.and_return(box_urls: ["bar"])
# Actual test
result = subject.find("foo", :virtualbox, ">= 0")
expect(result).to_not be_nil
expect(result).to be_kind_of(box_class)
expect(result.name).to eq("foo")
expect(result.metadata_url).to eq("bar")
end
it "returns latest version matching constraint" do

View File

@ -757,6 +757,11 @@ VF
collection = instance.boxes
collection.should be_kind_of(Vagrant::BoxCollection)
collection.directory.should == instance.boxes_path
# Reach into some internal state here but not sure how else
# to test this at the moment.
expect(collection.instance_variable_get(:@hook)).
to eq(instance.method(:hook))
end
describe "action runner" do