core: box URLs can be authenticated by hooking
This commit is contained in:
parent
45b17571ae
commit
7926f7f051
|
@ -57,8 +57,17 @@ module Vagrant
|
||||||
end
|
end
|
||||||
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
|
# 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
|
begin
|
||||||
metadata_url?(u, env)
|
metadata_url?(u, env)
|
||||||
rescue Errors::DownloaderError => e
|
rescue Errors::DownloaderError => e
|
||||||
|
@ -86,7 +95,8 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_metadata
|
if is_metadata
|
||||||
add_from_metadata(url.first, env, expanded)
|
url = [url.first, authed_urls.first]
|
||||||
|
add_from_metadata(url, env, expanded)
|
||||||
else
|
else
|
||||||
add_direct(url, env)
|
add_direct(url, env)
|
||||||
end
|
end
|
||||||
|
@ -118,12 +128,28 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a box given that the URL is a metadata document.
|
# 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)
|
def add_from_metadata(url, env, expanded)
|
||||||
original_url = env[:box_url]
|
original_url = env[:box_url]
|
||||||
provider = env[:box_provider]
|
provider = env[:box_provider]
|
||||||
provider = Array(provider) if provider
|
provider = Array(provider) if provider
|
||||||
version = env[:box_version]
|
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(
|
env[:ui].output(I18n.t(
|
||||||
"vagrant.box_loading_metadata",
|
"vagrant.box_loading_metadata",
|
||||||
name: Array(original_url).first))
|
name: Array(original_url).first))
|
||||||
|
@ -134,7 +160,8 @@ module Vagrant
|
||||||
|
|
||||||
metadata = nil
|
metadata = nil
|
||||||
begin
|
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|
|
File.open(metadata_path) do |f|
|
||||||
metadata = BoxMetadata.new(f)
|
metadata = BoxMetadata.new(f)
|
||||||
|
|
|
@ -44,6 +44,7 @@ module Vagrant
|
||||||
options ||= {}
|
options ||= {}
|
||||||
|
|
||||||
@directory = directory
|
@directory = directory
|
||||||
|
@hook = options[:hook]
|
||||||
@lock = Monitor.new
|
@lock = Monitor.new
|
||||||
@temp_root = options[:temp_dir_root]
|
@temp_root = options[:temp_dir_root]
|
||||||
@logger = Log4r::Logger.new("vagrant::box_collection")
|
@logger = Log4r::Logger.new("vagrant::box_collection")
|
||||||
|
@ -289,6 +290,12 @@ module Vagrant
|
||||||
metadata_url_file = box_directory.join("metadata_url")
|
metadata_url_file = box_directory.join("metadata_url")
|
||||||
metadata_url = metadata_url_file.read if metadata_url_file.file?
|
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(
|
return Box.new(
|
||||||
name, provider, v.to_s, provider_dir,
|
name, provider, v.to_s, provider_dir,
|
||||||
metadata_url: metadata_url,
|
metadata_url: metadata_url,
|
||||||
|
|
|
@ -258,7 +258,10 @@ module Vagrant
|
||||||
#
|
#
|
||||||
# @return [BoxCollection]
|
# @return [BoxCollection]
|
||||||
def boxes
|
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
|
end
|
||||||
|
|
||||||
# Returns the {Config::Loader} that can be used to load Vagrantflies
|
# Returns the {Config::Loader} that can be used to load Vagrantflies
|
||||||
|
|
|
@ -41,9 +41,18 @@ describe VagrantPlugins::CommandBox::Command::Update do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't update if they're up to date" do
|
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
|
subject.execute
|
||||||
|
|
||||||
|
expect(called).to be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does update if there is an update" do
|
it "does update if there is an update" do
|
||||||
|
@ -69,14 +78,21 @@ describe VagrantPlugins::CommandBox::Command::Update do
|
||||||
RAW
|
RAW
|
||||||
end
|
end
|
||||||
|
|
||||||
action_runner.should_receive(:run).with do |action, opts|
|
action_called = false
|
||||||
expect(opts[:box_url]).to eq(metadata_url.to_s)
|
action_runner.stub(:run) do |action, opts|
|
||||||
expect(opts[:box_provider]).to eq("virtualbox")
|
if opts[:box_provider]
|
||||||
expect(opts[:box_version]).to eq("1.1")
|
action_called = true
|
||||||
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")
|
||||||
|
end
|
||||||
|
|
||||||
|
opts
|
||||||
end
|
end
|
||||||
|
|
||||||
subject.execute
|
subject.execute
|
||||||
|
|
||||||
|
expect(action_called).to be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an error if there are multiple providers" do
|
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)
|
test_iso_env.box3("foo", "1.0", :vmware)
|
||||||
|
|
||||||
action_runner.should_receive(:run).with do |action, opts|
|
action_called = false
|
||||||
expect(opts[:box_url]).to eq(metadata_url.to_s)
|
action_runner.stub(:run) do |action, opts|
|
||||||
expect(opts[:box_provider]).to eq("vmware")
|
if opts[:box_provider]
|
||||||
expect(opts[:box_version]).to eq("1.1")
|
action_called = true
|
||||||
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")
|
||||||
|
end
|
||||||
|
|
||||||
|
opts
|
||||||
end
|
end
|
||||||
|
|
||||||
subject.execute
|
subject.execute
|
||||||
|
|
||||||
|
expect(action_called).to be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an error if that provider doesn't exist" do
|
it "raises an error if that provider doesn't exist" do
|
||||||
|
|
|
@ -14,6 +14,7 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
||||||
let(:app) { lambda { |env| } }
|
let(:app) { lambda { |env| } }
|
||||||
let(:env) { {
|
let(:env) { {
|
||||||
box_collection: box_collection,
|
box_collection: box_collection,
|
||||||
|
hook: Proc.new { |name, env| env },
|
||||||
tmp_path: Pathname.new(Dir.mktmpdir),
|
tmp_path: Pathname.new(Dir.mktmpdir),
|
||||||
ui: Vagrant::UI::Silent.new,
|
ui: Vagrant::UI::Silent.new,
|
||||||
} }
|
} }
|
||||||
|
@ -262,6 +263,60 @@ describe Vagrant::Action::Builtin::BoxAdd do
|
||||||
end
|
end
|
||||||
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
|
it "raises an error if no Vagrant server is set" do
|
||||||
tf = Tempfile.new("foo")
|
tf = Tempfile.new("foo")
|
||||||
tf.close
|
tf.close
|
||||||
|
|
|
@ -56,6 +56,42 @@ describe Vagrant::BoxCollection do
|
||||||
expect(result).to_not be_nil
|
expect(result).to_not be_nil
|
||||||
expect(result).to be_kind_of(box_class)
|
expect(result).to be_kind_of(box_class)
|
||||||
expect(result.name).to eq("foo")
|
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
|
end
|
||||||
|
|
||||||
it "returns latest version matching constraint" do
|
it "returns latest version matching constraint" do
|
||||||
|
|
|
@ -757,6 +757,11 @@ VF
|
||||||
collection = instance.boxes
|
collection = instance.boxes
|
||||||
collection.should be_kind_of(Vagrant::BoxCollection)
|
collection.should be_kind_of(Vagrant::BoxCollection)
|
||||||
collection.directory.should == instance.boxes_path
|
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
|
end
|
||||||
|
|
||||||
describe "action runner" do
|
describe "action runner" do
|
||||||
|
|
Loading…
Reference in New Issue