Commit 0690b999 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'djadmin-sync-up-dast-site-auth' into 'master'

Remove mock data from DAST Site Profiles

See merge request gitlab-org/gitlab!58735
parents 17c77aeb 9c92257c
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { resolvers } from 'ee/security_configuration/dast_profiles/graphql/provider';
import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo);
export default new VueApollo({
defaultClient: createDefaultClient(resolvers),
defaultClient: createDefaultClient(),
});
......@@ -17,15 +17,15 @@ query DastSiteProfiles($fullPath: ID!, $after: String, $before: String, $first:
editPath
validationStatus
referencedInSecurityPolicies
auth @client {
auth {
enabled
url
usernameField
passwordField
username
}
excludedUrls @client
requestHeaders @client
excludedUrls
requestHeaders
}
}
}
......
......@@ -4,21 +4,6 @@ import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo);
export const resolvers = {
DastSiteProfile: {
auth: () => ({
__typename: 'DastSiteProfileAuth',
enabled: true,
url: 'http://test.local/users/sign_in',
usernameField: 'username',
passwordField: 'password',
username: 'root',
}),
excludedUrls: () => ['http://test.local/sign_out', 'http://test.local/send_mail'],
requestHeaders: () => 'log-identifier: dast-active-scan',
},
};
export default new VueApollo({
defaultClient: createDefaultClient(resolvers, { assumeImmutableResults: true }),
defaultClient: createDefaultClient({}, { assumeImmutableResults: true }),
});
......@@ -31,7 +31,7 @@ export default {
},
data() {
const {
enabled,
enabled = false,
url,
username,
password,
......@@ -61,9 +61,6 @@ export default {
};
},
computed: {
showValidationOrInEditMode() {
return this.showValidation || this.isEditMode;
},
passwordFieldPlaceholder() {
return this.isEditMode ? '••••••••' : '';
},
......@@ -96,7 +93,7 @@ export default {
>
<gl-form-input
v-model="form.fields.url.value"
v-validation:[showValidationOrInEditMode]
v-validation:[showValidation]
name="url"
type="url"
required
......@@ -112,7 +109,7 @@ export default {
>
<gl-form-input
v-model="form.fields.username.value"
v-validation:[showValidationOrInEditMode]
v-validation:[showValidation]
autocomplete="off"
name="username"
type="text"
......@@ -127,7 +124,7 @@ export default {
>
<gl-form-input
v-model="form.fields.password.value"
v-validation:[showValidationOrInEditMode]
v-validation:[showValidation]
autocomplete="off"
name="password"
type="password"
......@@ -145,7 +142,7 @@ export default {
>
<gl-form-input
v-model="form.fields.usernameField.value"
v-validation:[showValidationOrInEditMode]
v-validation:[showValidation]
name="usernameField"
type="text"
required
......@@ -159,7 +156,7 @@ export default {
>
<gl-form-input
v-model="form.fields.passwordField.value"
v-validation:[showValidationOrInEditMode]
v-validation:[showValidation]
name="passwordField"
type="text"
required
......
......@@ -150,11 +150,6 @@ export default {
.map((url) => url.trim());
},
},
async mounted() {
if (this.isEdit) {
this.form.showValidation = true;
}
},
methods: {
onSubmit() {
const isAuthEnabled =
......
......@@ -4,6 +4,7 @@ module Projects
module Security
class DastSiteProfilesController < Projects::ApplicationController
include SecurityAndCompliancePermissions
include API::Helpers::GraphqlHelpers
before_action do
authorize_read_on_demand_scans!
......@@ -16,7 +17,31 @@ module Projects
end
def edit
@site_profile = DastSiteProfilesFinder.new(project_id: @project.id, id: params[:id]).execute.first! # rubocop: disable CodeReuse/ActiveRecord
global_id = Gitlab::GlobalId.as_global_id(params[:id], model_name: 'DastSiteProfile')
query = %(
{
project(fullPath: "#{project.full_path}") {
dastSiteProfile(id: "#{global_id}") {
id
name: profileName
targetUrl
excludedUrls
requestHeaders
auth { enabled url username usernameField password passwordField }
referencedInSecurityPolicies
}
}
}
)
@site_profile = run_graphql!(
query: query,
context: { current_user: current_user },
transform: -> (result) { result.dig('data', 'project', 'dastSiteProfile') }
)
return render_404 unless @site_profile
end
end
end
......
......@@ -3,11 +3,11 @@
module Types
module Dast
class SiteProfileAuthType < BaseObject
REDACTED_PASSWORD = '••••••••'
graphql_name 'DastSiteProfileAuth'
description 'Input type for DastSiteProfile authentication'
present_using ::Dast::SiteProfilePresenter
authorize :read_on_demand_scans
field :enabled, GraphQL::BOOLEAN_TYPE,
......@@ -39,12 +39,6 @@ module Types
field :password, GraphQL::STRING_TYPE,
null: true,
description: 'Redacted password to authenticate with on the target website.'
def password
return unless object.secret_variables.any? { |variable| variable.key == ::Dast::SiteProfileSecretVariable::PASSWORD }
REDACTED_PASSWORD
end
end
end
end
......@@ -7,6 +7,8 @@ module Types
graphql_name 'DastSiteProfile'
description 'Represents a DAST Site Profile'
present_using ::Dast::SiteProfilePresenter
authorize :read_on_demand_scans
expose_permissions Types::PermissionTypes::DastSiteProfile
......@@ -69,13 +71,6 @@ module Types
object.excluded_urls
end
def request_headers
return unless Feature.enabled?(:security_dast_site_profiles_additional_fields, object.project, default_enabled: :yaml)
return unless object.secret_variables.any? { |variable| variable.key == ::Dast::SiteProfileSecretVariable::REQUEST_HEADERS }
REDACTED_REQUEST_HEADERS
end
def normalized_target_url
DastSiteValidation.get_normalized_url_base(object.dast_site.url)
end
......
# frozen_string_literal: true
module Dast
class SiteProfilePresenter < Gitlab::View::Presenter::Delegated
REDACTED_PASSWORD = '••••••••'
REDACTED_REQUEST_HEADERS = '[Redacted]'
presents :site_profile
def password
return unless Feature.enabled?(:security_dast_site_profiles_additional_fields, site_profile.project, default_enabled: :yaml)
return unless site_profile.secret_variables.any? { |variable| variable.key == ::Dast::SiteProfileSecretVariable::PASSWORD }
REDACTED_PASSWORD
end
def request_headers
return unless Feature.enabled?(:security_dast_site_profiles_additional_fields, site_profile.project, default_enabled: :yaml)
return unless site_profile.secret_variables.any? { |variable| variable.key == ::Dast::SiteProfileSecretVariable::REQUEST_HEADERS }
REDACTED_REQUEST_HEADERS
end
end
end
......@@ -5,7 +5,5 @@
.js-dast-site-profile-form{ data: { full_path: @project.path_with_namespace,
profiles_library_path: project_security_configuration_dast_scans_path(@project, anchor: 'site-profiles'),
site_profile: { id: @site_profile.to_global_id.to_s, name: @site_profile.name, target_url: @site_profile.dast_site.url,
excluded_urls: ['https://example.com/logout', 'https://example.com/send_mail'], request_headers: 'new-header',
auth: { enabled: true, url: 'https://example.com', username: 'admin', usernameField: 'username', passwordField: 'password' }, referenced_in_security_policies: @site_profile.referenced_in_security_policies}.to_json,
site_profile: @site_profile.to_json,
on_demand_scans_path: new_project_on_demand_scan_path(@project) } }
......@@ -41,6 +41,11 @@ describe('DastSiteAuthSection', () => {
};
describe('authentication toggle', () => {
it('is set false by default', () => {
createComponent();
expect(findAuthCheckbox().vm.$attrs.checked).toBe(false);
});
it.each([true, false])(
'is set correctly when the "enabled" field is set to "%s"',
(authEnabled) => {
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Dast::SiteProfilePresenter do
let_it_be(:project) { create(:project) }
let_it_be(:dast_site_profile, reload: true) { create(:dast_site_profile, project: project) }
let(:presenter) { described_class.new(dast_site_profile) }
shared_examples 'a DAST on-demand secret variable' do
context 'when the feature flag is disabled' do
before do
stub_feature_flags(security_dast_site_profiles_additional_fields: false)
end
it { is_expected.to be_nil }
end
context 'when the feature flag is enabled' do
context 'when there is no associated secret variable' do
it { is_expected.to be_nil }
end
context 'when there an associated secret variable' do
it 'is redacted' do
create(:dast_site_profile_secret_variable, dast_site_profile: dast_site_profile, key: key)
expect(subject).to eq(redacted_value)
end
end
end
end
describe '#password' do
let(:key) { Dast::SiteProfileSecretVariable::PASSWORD }
let(:redacted_value) { described_class::REDACTED_PASSWORD }
subject { presenter.password }
it_behaves_like 'a DAST on-demand secret variable'
end
describe '#request_headers' do
let(:key) { Dast::SiteProfileSecretVariable::REQUEST_HEADERS }
let(:redacted_value) { described_class::REDACTED_REQUEST_HEADERS }
subject { presenter.request_headers }
it_behaves_like 'a DAST on-demand secret variable'
end
end
......@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Projects::Security::DastSiteProfilesController, type: :request do
include GraphqlHelpers
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:dast_site_profile) { create(:dast_site_profile, project: project) }
......@@ -87,18 +89,52 @@ RSpec.describe Projects::Security::DastSiteProfilesController, type: :request do
let(:path) { edit_path }
end
context 'record does not exist' do
let(:dast_site_profile) { 0 }
context 'feature available and user authorized' do
before do
with_feature_available
with_user_authorized
end
it 'sees a 404 error' do
get edit_path
context 'record exists' do
before do
create(:dast_site_profile_secret_variable, dast_site_profile: dast_site_profile, key: Dast::SiteProfileSecretVariable::PASSWORD)
create(:dast_site_profile_secret_variable, dast_site_profile: dast_site_profile, key: Dast::SiteProfileSecretVariable::REQUEST_HEADERS)
end
it 'includes a serialized dast_profile in the response body' do
get edit_path
json_data = {
id: global_id_of(dast_site_profile),
name: dast_site_profile.name,
targetUrl: dast_site_profile.dast_site.url,
excludedUrls: dast_site_profile.excluded_urls,
requestHeaders: Dast::SiteProfilePresenter::REDACTED_REQUEST_HEADERS,
auth: {
enabled: dast_site_profile.auth_enabled,
url: dast_site_profile.auth_url,
username: dast_site_profile.auth_username,
usernameField: dast_site_profile.auth_username_field,
password: Dast::SiteProfilePresenter::REDACTED_PASSWORD,
passwordField: dast_site_profile.auth_password_field
},
referencedInSecurityPolicies: dast_site_profile.referenced_in_security_policies
}.to_json
form = Nokogiri::HTML.parse(response.body).at_css('div.js-dast-site-profile-form')
expect(form.attributes['data-site-profile'].value).to include(json_data)
end
end
context 'record does not exist' do
let(:dast_site_profile) { 0 }
it 'sees a 404 error' do
get edit_path
expect(response).to have_gitlab_http_status(:not_found)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
......
......@@ -4,12 +4,10 @@ require 'spec_helper'
RSpec.describe "projects/security/dast_site_profiles/edit", type: :view do
let_it_be(:site_profile) { create(:dast_site_profile) }
let_it_be(:site_profile_gid) { ::URI::GID.parse("gid://gitlab/DastSiteProfile/#{site_profile.id}") }
before do
assign(:project, site_profile.project)
assign(:site_profile, site_profile)
assign(:site_profile_gid, site_profile_gid)
render
end
......@@ -24,10 +22,4 @@ RSpec.describe "projects/security/dast_site_profiles/edit", type: :view do
it 'passes DAST profiles library URL' do
expect(rendered).to include '/security/configuration/dast_scans#site-profiles'
end
it 'passes DAST site profile\'s data' do
expect(rendered).to include site_profile_gid.to_s
expect(rendered).to include site_profile.name
expect(rendered).to include site_profile.dast_site.url
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