From ec9174441ee23d25bf85c94aff31b31bc327e3a6 Mon Sep 17 00:00:00 2001 From: "Alysson A. Costa" Date: Mon, 7 Dec 2020 13:46:02 -0300 Subject: [PATCH 1/3] Add authentication resources --- .gitignore | 4 ++++ bin/setup | 10 +++++++++- resources/registry_authentication/.keep | 0 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 resources/registry_authentication/.keep diff --git a/.gitignore b/.gitignore index b04a8c8..18ebe81 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ # rspec failure tracking .rspec_status + +resources/registry_authentication/*.key +resources/registry_authentication/*.crt +resources/registry_authentication/htpasswd \ No newline at end of file diff --git a/bin/setup b/bin/setup index a859511..38b3a1e 100755 --- a/bin/setup +++ b/bin/setup @@ -18,5 +18,13 @@ then else echo "Running bundle install" bundle install + + echo "Creating self-signed certificate to use in tests" + openssl req -newkey rsa:2048 -nodes -keyout resources/registry_authentication/registry_auth.key -x509 -days 365 -out resources/registry_authentication/registry_auth.crt -subj "/C=CL/ST=Santiago/L=Santiago/O=dockerapi/OU=dockerapi/CN=dockerapi" + + echo "Creating htpasswd file to use in tests" + docker run --rm --entrypoint htpasswd registry:2.7.0 -Bbn janedoe password > resources/registry_authentication/htpasswd + docker image rm registry:2.7.0 echo "Run this script as root for further configurations" -fi \ No newline at end of file +fi + diff --git a/resources/registry_authentication/.keep b/resources/registry_authentication/.keep new file mode 100644 index 0000000..e69de29 From b6b94995ecf6c7f8cdee7c6bdd5da46509a3564e Mon Sep 17 00:00:00 2001 From: "Alysson A. Costa" Date: Mon, 7 Dec 2020 15:02:23 -0300 Subject: [PATCH 2/3] WIP: adding authentication tests, resolves #4 --- spec/endpoints/image_spec.rb | 66 ++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/spec/endpoints/image_spec.rb b/spec/endpoints/image_spec.rb index 8498295..1e25358 100644 --- a/spec/endpoints/image_spec.rb +++ b/spec/endpoints/image_spec.rb @@ -189,4 +189,70 @@ it { expect(subject.distribution(image).status).to eq(200) } it { expect(subject.distribution("doesn-exist").status).to eq(403) } end + + describe "authentication" do + original = "registry:2.7.0" + local = "localhost:5000/janedoe/test:latest" + before(:all) do + # Download image + described_class.new.create(fromImage: original) + + # Create container + container = Docker::API::Container.new + container.create( {name: "registry"}, { + Image: original, + HostConfig: { + PortBindings: {"5000/tcp": [ {HostIp: "0.0.0.0", HostPort: "5000"} ] }, + Binds: [ + "#{File.expand_path(File.dirname(__FILE__))}/../../resources/registry_authentication:/auth", + "#{File.expand_path(File.dirname(__FILE__))}/../../resources/registry_authentication:/certs"]}, + Env: [ + "REGISTRY_AUTH=htpasswd", + "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", + "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd", + "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry_auth.crt", + "REGISTRY_HTTP_TLS_KEY=/certs/registry_auth.key", + + ], + }) + # Start container + container.start("registry") + + # Create local repository + described_class.new.tag(original, repo: local) + end + + #Image#push + # Right credential + # Wrong credential + it { expect(subject.push(local, {}, {username: "janedoe", password: "password"}).status).to eq(200) } + it { expect(subject.push(local, {}, {username: "janedoe", password: "password"}).json.last[:aux][:Size]).to be > 0 } + it { expect(subject.push(local, {}, {username: "janedoe", password: "wrong-password"}).status).to eq(200) } + it { expect(subject.push(local, {}, {username: "janedoe", password: "wrong-password"}).json.last[:error]).to match(/(unauthorized: authentication required)/) } + + #Image#build + # Right credential + # Wrong credential + #Image#create + # Right credential + # Unexisting repo + # Wrong credential + #Image#distribution + # Right credential + # Unexisting repo + # Wrong credential + + after(:all) do + container = Docker::API::Container.new + # Stop container + container.stop("registry") + # Remove container + container.remove("registry") + # Remove image + described_class.new.remove(original) + # Remove volumes + Docker::API::Volume.new.prune + end + + end end \ No newline at end of file From 816e0fe706098810bb3b81049428fd5f5e47eb56 Mon Sep 17 00:00:00 2001 From: "Alysson A. Costa" Date: Mon, 7 Dec 2020 17:18:42 -0300 Subject: [PATCH 3/3] Add authentication test --- spec/endpoints/image_spec.rb | 47 +++++++++++++++--------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/spec/endpoints/image_spec.rb b/spec/endpoints/image_spec.rb index 1e25358..6020280 100644 --- a/spec/endpoints/image_spec.rb +++ b/spec/endpoints/image_spec.rb @@ -194,10 +194,8 @@ original = "registry:2.7.0" local = "localhost:5000/janedoe/test:latest" before(:all) do - # Download image described_class.new.create(fromImage: original) - # Create container container = Docker::API::Container.new container.create( {name: "registry"}, { Image: original, @@ -215,42 +213,37 @@ ], }) - # Start container container.start("registry") - # Create local repository described_class.new.tag(original, repo: local) end + + describe ".push" do + it { expect(subject.push(local, {}, {username: "janedoe", password: "password"}).status).to eq(200) } + it { expect(subject.push(local, {}, {username: "janedoe", password: "password"}).json.last[:aux][:Size]).to be > 0 } + it { expect(subject.push(local, {}, {username: "janedoe", password: "wrong-password"}).status).to eq(200) } + it { expect(subject.push(local, {}, {username: "janedoe", password: "wrong-password"}).json.last[:error]).to match(/(unauthorized: authentication required)/) } + end + + describe ".create" do + it { expect(subject.create({fromImage: local}, {username: "janedoe", password: "password"}).status).to eq(200) } + it { expect(subject.create({fromImage: "localhost:5000/janedoe/doesnt-exist:latest"}, {username: "janedoe", password: "password"}).status).to eq(404) } + it { expect(subject.create({fromImage: local}, {username: "janedoe", password: "wrong-password"}).status).to eq(500) } + end - #Image#push - # Right credential - # Wrong credential - it { expect(subject.push(local, {}, {username: "janedoe", password: "password"}).status).to eq(200) } - it { expect(subject.push(local, {}, {username: "janedoe", password: "password"}).json.last[:aux][:Size]).to be > 0 } - it { expect(subject.push(local, {}, {username: "janedoe", password: "wrong-password"}).status).to eq(200) } - it { expect(subject.push(local, {}, {username: "janedoe", password: "wrong-password"}).json.last[:error]).to match(/(unauthorized: authentication required)/) } + describe ".distribute" do + it { expect(subject.distribution(local, {username: "janedoe", password: "password"}).status).to eq(200) } + it { expect(subject.distribution("localhost:5000/janedoe/doesnt-exist:latest", {username: "janedoe", password: "password"}).status).to eq(404) } + it { expect(subject.distribution(local, {username: "janedoe", password: "wrong-password"}).status).to eq(401) } + end - #Image#build - # Right credential - # Wrong credential - #Image#create - # Right credential - # Unexisting repo - # Wrong credential - #Image#distribution - # Right credential - # Unexisting repo - # Wrong credential - after(:all) do container = Docker::API::Container.new - # Stop container container.stop("registry") - # Remove container container.remove("registry") - # Remove image + described_class.new.remove(original) - # Remove volumes + Docker::API::Volume.new.prune end