Commit 9f52b46f authored by Jan Provaznik's avatar Jan Provaznik

Merge branch 'support-header-validation-for-on-demand-dast-260341' into 'master'

Add header validation to DastSiteValidationWorker

See merge request gitlab-org/gitlab!44314
parents 6cf719ee d172a2b7
# frozen_string_literal: true
class DastSiteValidation < ApplicationRecord
HEADER = 'Gitlab-On-Demand-DAST'.freeze
belongs_to :dast_site_token
has_many :dast_sites
......@@ -13,7 +15,7 @@ class DastSiteValidation < ApplicationRecord
before_create :set_normalized_url_base
enum validation_strategy: { text_file: 0 }
enum validation_strategy: { text_file: 0, header: 1 }
delegate :project, to: :dast_site_token, allow_nil: true
......
......@@ -38,11 +38,20 @@ module DastSiteValidations
end
def token_found?(response)
response.body.include?(dast_site_validation.dast_site_token.token)
token = dast_site_validation.dast_site_token.token
case dast_site_validation.validation_strategy
when 'text_file'
response.body.include?(token)
when 'header'
response.headers[DastSiteValidation::HEADER] == token
else
false
end
end
def validate!(response)
raise TokenNotFound.new('Could not find token in response body') unless token_found?(response)
raise TokenNotFound.new('Could not find token') unless token_found?(response)
dast_site_validation.pass
end
......
---
title: Add header validation to DastSiteValidationWorker
merge_request: 44314
author:
type: added
......@@ -51,7 +51,7 @@ RSpec.describe DastSiteValidation, type: :model do
describe 'enums' do
let(:validation_strategies) do
{ text_file: 0 }
{ text_file: 0, header: 1 }
end
it { is_expected.to define_enum_for(:validation_strategy).with_values(validation_strategies) }
......
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe DastSiteValidations::ValidateService do
let(:dast_site_validation) { create(:dast_site_validation) }
let(:token) { dast_site_validation.dast_site_token.token }
subject do
described_class.new(
......@@ -35,11 +36,7 @@ RSpec.describe DastSiteValidations::ValidateService do
before do
stub_licensed_features(security_on_demand_scans: true)
stub_feature_flags(security_on_demand_scans_site_validation: true)
stub_request(:get, dast_site_validation.validation_url).to_return(body: response_body)
end
let(:response_body) do
dast_site_validation.dast_site_token.token
stub_request(:get, dast_site_validation.validation_url).to_return(body: token)
end
it 'validates the url before making an http request' do
......@@ -47,72 +44,100 @@ RSpec.describe DastSiteValidations::ValidateService do
aggregate_failures do
expect(Gitlab::UrlBlocker).to receive(:validate!).and_return([uri, nil])
expect(Gitlab::HTTP).to receive(:get).with(uri).and_return(double('response', body: dast_site_validation.dast_site_token.token))
expect(Gitlab::HTTP).to receive(:get).with(uri).and_return(double('response', body: token))
end
subject
end
context 'when the request body contains the token' do
it 'calls dast_site_validation#start' do
expect(dast_site_validation).to receive(:start)
subject
end
context 'when validation has already been attempted' do
let_it_be(:dast_site_validation) { create(:dast_site_validation, state: :failed) }
it 'calls dast_site_validation#pass' do
expect(dast_site_validation).to receive(:pass)
it 'marks the validation as a retry' do
freeze_time do
subject
subject
expect(dast_site_validation.reload.validation_last_retried_at).to eq(Time.now.utc)
end
end
end
it 'marks the validation successful' do
subject
shared_examples 'a validation' do
context 'when the token is found' do
it 'calls dast_site_validation#start' do
expect(dast_site_validation).to receive(:start)
expect(dast_site_validation.reload.state).to eq('passed')
end
subject
end
context 'when validation has already started' do
let(:dast_site_validation) { create(:dast_site_validation, state: :inprogress) }
it 'calls dast_site_validation#pass' do
expect(dast_site_validation).to receive(:pass)
it 'does not call dast_site_validation#pass' do
expect(dast_site_validation).not_to receive(:start)
subject
end
it 'marks the validation successful' do
subject
expect(dast_site_validation.reload.state).to eq('passed')
end
end
context 'when validation is already complete' do
let(:dast_site_validation) { create(:dast_site_validation, state: :passed) }
context 'when validation has already started' do
before do
dast_site_validation.update_column(:state, :inprogress)
end
it 'does not re-validate' do
expect(Gitlab::HTTP).not_to receive(:get)
it 'does not call dast_site_validation#pass' do
expect(dast_site_validation).not_to receive(:start)
subject
subject
end
end
context 'when validation is already complete' do
before do
dast_site_validation.update_column(:state, :passed)
end
it 'does not re-validate' do
expect(Gitlab::HTTP).not_to receive(:get)
subject
end
end
end
end
context 'when the request body does not contain the token' do
let(:response_body) do
SecureRandom.hex
context 'when the token is not found' do
let(:token) do
SecureRandom.hex
end
it 'raises an exception' do
expect { subject }.to raise_error(DastSiteValidations::ValidateService::TokenNotFound)
end
end
end
context 'when validation_strategy=text_file' do
let(:dast_site_validation) { create(:dast_site_validation, validation_strategy: :text_file) }
it 'raises an exception' do
expect { subject }.to raise_error(DastSiteValidations::ValidateService::TokenNotFound)
before do
stub_request(:get, dast_site_validation.validation_url).to_return(body: token)
end
it_behaves_like 'a validation'
end
context 'when validation has already been attempted' do
let_it_be(:dast_site_validation) { create(:dast_site_validation, state: :failed) }
context 'when validation_strategy=header' do
let(:dast_site_validation) { create(:dast_site_validation, validation_strategy: :header) }
it 'marks the validation as a retry' do
freeze_time do
subject
before do
headers = { DastSiteValidation::HEADER => token }
expect(dast_site_validation.reload.validation_last_retried_at).to eq(Time.now.utc)
end
stub_request(:get, dast_site_validation.validation_url).to_return(headers: headers)
end
it_behaves_like 'a validation'
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment