Skip to content
Snippets Groups Projects
git_http_spec.rb 7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Douwe Maan's avatar
    Douwe Maan committed
    require "spec_helper"
    
    
    describe 'Git HTTP requests', lib: true do
    
    Douwe Maan's avatar
    Douwe Maan committed
      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
    
              download('doesnt/exist.git') do |response|
                expect(response.status).to eq(401)
              end
    
    Douwe Maan's avatar
    Douwe Maan committed
            end
          end
    
          context "when username and password are provided" do
            context "when authentication fails" do
              it "responds with status 401" do
    
                download('doesnt/exist.git', user: user.username, password: "nope") do |response|
                  expect(response.status).to eq(401)
                end
    
    Douwe Maan's avatar
    Douwe Maan committed
              end
            end
    
            context "when authentication succeeds" do
              it "responds with status 404" do
    
                download('/doesnt/exist.git', user: user.username, password: user.password) do |response|
                  expect(response.status).to eq(404)
                end
    
    Douwe Maan's avatar
    Douwe Maan committed
              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)
    
    
            download("/#{wiki.repository.path_with_namespace}.git") do |response|
              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
    
    Douwe Maan's avatar
    Douwe Maan committed
        context "when the project exists" do
    
          let(:path) { "#{project.path_with_namespace}.git" }
          let(:env) { {} }
    
    Douwe Maan's avatar
    Douwe Maan committed
    
          context "when the project is public" do
    
    Douwe Maan's avatar
    Douwe Maan committed
              project.update_attribute(:visibility_level, Project::PUBLIC)
    
            end
            
            it "responds with status 200" do
    
              download(path, env) do |response|
                expect(response.status).to eq(200)
              end
    
    Douwe Maan's avatar
    Douwe Maan committed
            end
    
            
            context 'but git-upload-pack is disabled' do
              it "responds with status 404" do
                allow(Gitlab.config.gitlab_shell).to receive(:upload_pack).and_return(false)
    
                download(path, env) do |response|
                  expect(response.status).to eq(404)
                end
              end
            end
    
    Douwe Maan's avatar
    Douwe Maan committed
          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
    
                download(path, env) do |response|
                  expect(response.status).to eq(401)
                end
    
    Douwe Maan's avatar
    Douwe Maan committed
              end
            end
    
            context "when username and password are provided" do
    
              let(:env) { { user: user.username, password: 'nope' } }
    
    Douwe Maan's avatar
    Douwe Maan committed
              context "when authentication fails" do
                it "responds with status 401" do
    
                  download(path, env) do |response|
                    expect(response.status).to eq(401)
                  end
    
    Douwe Maan's avatar
    Douwe Maan committed
                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, env)
    
                    expect(response.status).to eq(401)
    
    Douwe Maan's avatar
    Douwe Maan committed
              end
    
              context "when authentication succeeds" do
    
                let(:env) { { user: user.username, password: user.password } }
    
    Douwe Maan's avatar
    Douwe Maan committed
                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
    
    Douwe Maan's avatar
    Douwe Maan committed
                      user.block
                      project.team << [user, :master]
    
    
                      download(path, env) do |response|
                        expect(response.status).to eq(404)
                      end
    
    Douwe Maan's avatar
    Douwe Maan committed
                    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, env)
    
                      expect(response.status).to eq(200)
    
    Douwe Maan's avatar
    Douwe Maan committed
                    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)
    
    Douwe Maan's avatar
    Douwe Maan committed
                end
    
                context "when the user doesn't have access to the project" do
                  it "responds with status 404" do
    
                    download(path, user: user.username, password: user.password) do |response|
                      expect(response.status).to eq(404)
                    end
    
    Douwe Maan's avatar
    Douwe Maan committed
                  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 "#{project.path_with_namespace}.git", user: 'gitlab-ci-token', password: token
    
                expect(response.status).to eq(200)
    
    Douwe Maan's avatar
    Douwe Maan committed
              end
            end
          end
        end
      end
    
      def clone_get(project, options={})
        get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password))
      end
    
      def clone_post(project, options={})
        post "/#{project}/git-upload-pack", {}, auth_env(*options.values_at(:user, :password))
    
      def download(project, user: nil, password: nil)
        args = [project, {user: user, password: password}]
    
        clone_get *args
        yield response
    
        clone_post *args
        yield response
      end
    
      def auth_env(user, password)
        if user && password
          { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password) }
        else
          {}
        end
      end
    
    Douwe Maan's avatar
    Douwe Maan committed
    end