diff options
author | Jacob Vosmaer <contact@jacobvosmaer.nl> | 2016-03-23 16:04:09 +0300 |
---|---|---|
committer | Jacob Vosmaer <contact@jacobvosmaer.nl> | 2016-03-23 16:09:52 +0300 |
commit | 19a5e7c95e91baca58836ad3ae189190c9ba4ca2 (patch) | |
tree | d084a6e82a3b39c958e067e15bba7c25b34fd35a /spec/requests/git_http_spec.rb | |
parent | 7124e5a44c045dae511c0cac65c936b445c1a5b6 (diff) |
Test Grack::Auth via a request spec
Diffstat (limited to 'spec/requests/git_http_spec.rb')
-rw-r--r-- | spec/requests/git_http_spec.rb | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb new file mode 100644 index 00000000000..7e274b4209b --- /dev/null +++ b/spec/requests/git_http_spec.rb @@ -0,0 +1,190 @@ +require "spec_helper" + +describe 'Git HTTP requests', lib: true do + let(:user) { create(:user) } + let(:project) { create(:project) } + + describe "#call" do + context "when the project doesn't exist" do + context "when no authentication is provided" do + it "responds with status 401" do + clone_get '/doesnt/exist.git/info/refs' + + expect(response.status).to eq(401) + end + end + + context "when username and password are provided" do + context "when authentication fails" do + it "responds with status 401" do + clone_get '/doesnt/exist.git/info/refs', user: user.username, password: "nope" + + expect(response.status).to eq(401) + end + end + + context "when authentication succeeds" do + it "responds with status 404" do + clone_get '/doesnt/exist.git/info/refs', user: user.username, password: user.password + + expect(response.status).to eq(404) + end + end + end + end + + context "when the Wiki for a project exists" do + it "responds with the right project" do + wiki = ProjectWiki.new(project) + project.update_attribute(:visibility_level, Project::PUBLIC) + + clone_get "/#{wiki.repository.path_with_namespace}.git/info/refs" + json_body = ActiveSupport::JSON.decode(response.body) + + expect(response.status).to eq(200) + expect(json_body['RepoPath']).to include(wiki.repository.path_with_namespace) + end + end + + context "when the project exists" do + let(:path) { clone_path(project) } + + context "when the project is public" do + it "responds with status 200" do + project.update_attribute(:visibility_level, Project::PUBLIC) + clone_get path + + expect(response.status).to eq(200) + end + end + + context "when the project is private" do + before do + project.update_attribute(:visibility_level, Project::PRIVATE) + end + + context "when no authentication is provided" do + it "responds with status 401" do + clone_get path + + expect(response.status).to eq(401) + end + end + + context "when username and password are provided" do + context "when authentication fails" do + it "responds with status 401" do + clone_get path, user: user.username, password: 'nope' + + expect(response.status).to eq(401) + end + + context "when the user is IP banned" do + it "responds with status 401" do + expect(Rack::Attack::Allow2Ban).to receive(:filter).and_return(true) + allow_any_instance_of(Rack::Request).to receive(:ip).and_return('1.2.3.4') + + clone_get path, user: user.username, password: 'nope' + + expect(response.status).to eq(401) + end + end + end + + context "when authentication succeeds" do + context "when the user has access to the project" do + before do + project.team << [user, :master] + end + + context "when the user is blocked" do + it "responds with status 404" do + user.block + project.team << [user, :master] + + clone_get path, user: user.username, password: user.password + + expect(response.status).to eq(404) + end + end + + context "when the user isn't blocked" do + it "responds with status 200" do + expect(Rack::Attack::Allow2Ban).to receive(:reset) + + clone_get path, user: user.username, password: user.password + + expect(response.status).to eq(200) + end + end + + context "when blank password attempts follow a valid login" do + def attempt_login(include_password) + password = include_password ? user.password : "" + clone_get path, user: user.username, password: password + response.status + end + + it "repeated attempts followed by successful attempt" do + options = Gitlab.config.rack_attack.git_basic_auth + maxretry = options[:maxretry] - 1 + ip = '1.2.3.4' + + allow_any_instance_of(Rack::Request).to receive(:ip).and_return(ip) + Rack::Attack::Allow2Ban.reset(ip, options) + + maxretry.times.each do + expect(attempt_login(false)).to eq(401) + end + + expect(attempt_login(true)).to eq(200) + expect(Rack::Attack::Allow2Ban.banned?(ip)).to be_falsey + + maxretry.times.each do + expect(attempt_login(false)).to eq(401) + end + + Rack::Attack::Allow2Ban.reset(ip, options) + end + end + end + + context "when the user doesn't have access to the project" do + it "responds with status 404" do + clone_get path, user: user.username, password: user.password + + expect(response.status).to eq(404) + end + end + end + end + + context "when a gitlab ci token is provided" do + it "responds with status 200" do + token = "123" + project = FactoryGirl.create :empty_project + project.update_attributes(runners_token: token, builds_enabled: true) + + clone_get clone_path(project), user: 'gitlab-ci-token', password: token + + expect(response.status).to eq(200) + end + end + end + end + end + + def clone_get(url, user: nil, password: nil) + if user && password + env = { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password) } + else + env = {} + end + + get url, { 'service' => 'git-upload-pack' }, env + end + + def clone_path(project) + "/#{project.path_with_namespace}.git/info/refs" + end +end |