Commit 7291ce5a authored by Dheeraj Joshi's avatar Dheeraj Joshi Committed by Kushal Pandya

Allow editing DAST site profile fields

This should add support for editing
auth related fields in DAST Site Profile
form
parent 0e9e1d42
<script>
import { GlFormGroup, GlFormInput, GlFormCheckbox } from '@gitlab/ui';
import { initFormField } from 'ee/security_configuration/utils';
import { __ } from '~/locale';
import validation from '~/vue_shared/directives/validation';
export default {
......@@ -13,7 +14,7 @@ export default {
validation: validation(),
},
props: {
fields: {
value: {
type: Object,
required: false,
default: () => ({}),
......@@ -26,32 +27,41 @@ export default {
},
data() {
const {
authEnabled,
authenticationUrl,
userName,
enabled,
url,
username,
password,
// default to commonly used names for `userName` and `password` fields in authentcation forms
userNameFormField = 'username',
passwordFormField = 'password',
} = this.fields;
// default to commonly used names for `username` and `password` fields in authentcation forms
usernameField = 'username',
passwordField = 'password',
} = this.value.fields;
const isEditMode = Object.keys(this.value.fields).length > 0;
return {
form: {
state: false,
fields: {
authEnabled: initFormField({ value: authEnabled, skipValidation: true }),
authenticationUrl: initFormField({ value: authenticationUrl }),
userName: initFormField({ value: userName }),
password: initFormField({ value: password }),
userNameFormField: initFormField({ value: userNameFormField }),
passwordFormField: initFormField({ value: passwordFormField }),
enabled: initFormField({ value: enabled, skipValidation: true }),
url: initFormField({ value: url }),
username: initFormField({ value: username }),
password: isEditMode
? initFormField({ value: password, required: false, skipValidation: true })
: initFormField({ value: password }),
usernameField: initFormField({ value: usernameField }),
passwordField: initFormField({ value: passwordField }),
},
},
isEditMode,
isSensitiveFieldRequired: !isEditMode,
};
},
computed: {
showValidationOrInEditMode() {
return this.showValidation || Object.keys(this.fields).length > 0;
return this.showValidation || this.isEditMode;
},
sensitiveFieldPlaceholder() {
return this.isEditMode ? __('[Unchanged]') : '';
},
},
watch: {
......@@ -68,41 +78,41 @@ export default {
<template>
<section>
<gl-form-group :label="s__('DastProfiles|Authentication')">
<gl-form-checkbox v-model="form.fields.authEnabled.value">{{
<gl-form-checkbox v-model="form.fields.enabled.value" data-testid="auth-enable-checkbox">{{
s__('DastProfiles|Enable Authentication')
}}</gl-form-checkbox>
</gl-form-group>
<div v-if="form.fields.authEnabled.value" data-testid="auth-form">
<div v-if="form.fields.enabled.value" data-testid="auth-form">
<div class="row">
<gl-form-group
:label="s__('DastProfiles|Authentication URL')"
:invalid-feedback="form.fields.authenticationUrl.feedback"
:invalid-feedback="form.fields.url.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.authenticationUrl.value"
v-model="form.fields.url.value"
v-validation:[showValidationOrInEditMode]
name="authenticationUrl"
name="url"
type="url"
required
:state="form.fields.authenticationUrl.state"
:state="form.fields.url.state"
/>
</gl-form-group>
</div>
<div class="row">
<gl-form-group
:label="s__('DastProfiles|Username')"
:invalid-feedback="form.fields.userName.feedback"
:invalid-feedback="form.fields.username.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.userName.value"
v-model="form.fields.username.value"
v-validation:[showValidationOrInEditMode]
autocomplete="off"
name="userName"
name="username"
type="text"
required
:state="form.fields.userName.state"
:state="form.fields.username.state"
/>
</gl-form-group>
<gl-form-group
......@@ -116,7 +126,8 @@ export default {
autocomplete="off"
name="password"
type="password"
required
:placeholder="sensitiveFieldPlaceholder"
:required="isSensitiveFieldRequired"
:state="form.fields.password.state"
/>
</gl-form-group>
......@@ -124,30 +135,30 @@ export default {
<div class="row">
<gl-form-group
:label="s__('DastProfiles|Username form field')"
:invalid-feedback="form.fields.userNameFormField.feedback"
:invalid-feedback="form.fields.usernameField.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.userNameFormField.value"
v-model="form.fields.usernameField.value"
v-validation:[showValidationOrInEditMode]
name="userNameFormField"
name="usernameField"
type="text"
required
:state="form.fields.userNameFormField.state"
:state="form.fields.usernameField.state"
/>
</gl-form-group>
<gl-form-group
:label="s__('DastProfiles|Password form field')"
:invalid-feedback="form.fields.passwordFormField.feedback"
:invalid-feedback="form.fields.passwordField.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.passwordFormField.value"
v-model="form.fields.passwordField.value"
v-validation:[showValidationOrInEditMode]
name="passwordFormField"
name="passwordField"
type="text"
required
:state="form.fields.passwordFormField.state"
:state="form.fields.passwordField.state"
/>
</gl-form-group>
</div>
......
......@@ -56,7 +56,7 @@ export default {
},
},
data() {
const { name = '', targetUrl = '', excludedUrls = '', requestHeaders = '' } =
const { name = '', targetUrl = '', excludedUrls = '', requestHeaders = '', auth = {} } =
this.siteProfile || {};
const form = {
......@@ -76,7 +76,7 @@ export default {
return {
form,
authSection: {},
authSection: { fields: auth },
initialFormValues: serializeFormObject(form.fields),
isLoading: false,
hasAlert: false,
......@@ -126,7 +126,7 @@ export default {
onSubmit() {
const isAuthEnabled =
this.glFeatures.securityDastSiteProfilesAdditionalFields &&
this.authSection.fields.authEnabled.value;
this.authSection.fields.enabled.value;
this.form.showValidation = true;
......@@ -143,7 +143,7 @@ export default {
fullPath: this.fullPath,
...(this.isEdit ? { id: this.siteProfile.id } : {}),
...serializeFormObject(this.form.fields),
...(isAuthEnabled ? serializeFormObject(this.authSection.fields) : {}),
auth: isAuthEnabled ? serializeFormObject(this.authSection.fields) : {},
},
};
......
......@@ -5,5 +5,7 @@
.js-dast-site-profile-form{ data: { full_path: @project.path_with_namespace,
profiles_library_path: project_security_configuration_dast_profiles_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 }.to_json,
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', request_headers: 'new-header',
auth: { enabled: true, url: 'https://example.com', username: 'admin', usernameField: 'username', passwordField: 'password' }}.to_json,
on_demand_scans_path: Feature.enabled?(:dast_saved_scans, @project, default_enabled: :yaml) ? new_project_on_demand_scan_path(@project) : project_on_demand_scans_path(@project) } }
......@@ -528,9 +528,9 @@ describe('OnDemandScansForm', () => {
describe('site profile summary', () => {
const [authEnabledProfile] = siteProfiles;
const selectSiteProfile = (profile) => {
const selectSiteProfile = async (profile) => {
subject.find(SiteProfileSelector).vm.$emit('input', profile.id);
return subject.vm.$nextTick();
await subject.vm.$nextTick();
};
beforeEach(() => {
......
......@@ -35,6 +35,7 @@ export const siteProfiles = [
usernameField: 'username',
passwordField: 'password',
username: 'admin',
password: 'password',
},
excludedUrls: 'https://foo.com/logout,https://foo.com/send_mail',
requestHeaders: 'log-identifier: dast-active-scan',
......
......@@ -6,11 +6,11 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
describe('DastSiteAuthSection', () => {
let wrapper;
const createComponent = ({ fields } = {}) => {
const createComponent = ({ fields = {} } = {}) => {
wrapper = extendedWrapper(
mount(DastSiteAuthSection, {
propsData: {
fields,
value: { fields },
},
}),
);
......@@ -40,9 +40,9 @@ describe('DastSiteAuthSection', () => {
describe('authentication toggle', () => {
it.each([true, false])(
'is set correctly when the "authEnabled" field is set to "%s"',
'is set correctly when the "enabled" field is set to "%s"',
(authEnabled) => {
createComponent({ fields: { authEnabled } });
createComponent({ fields: { enabled: authEnabled } });
expect(findAuthCheckbox().vm.$attrs.checked).toBe(authEnabled);
},
);
......@@ -57,7 +57,7 @@ describe('DastSiteAuthSection', () => {
'makes the component emit an "input" event when changed',
async (enabled) => {
await setAuthentication({ enabled });
expect(getLatestInputEventPayload().fields.authEnabled.value).toBe(enabled);
expect(getLatestInputEventPayload().fields.enabled.value).toBe(enabled);
},
);
});
......@@ -68,11 +68,11 @@ describe('DastSiteAuthSection', () => {
});
const inputFieldsWithValues = {
authenticationUrl: 'http://www.gitlab.com',
userName: 'foo',
url: 'http://www.gitlab.com',
username: 'foo',
password: 'foo',
userNameFormField: 'foo',
passwordFormField: 'foo',
usernameField: 'foo',
passwordField: 'foo',
};
const inputFieldNames = Object.keys(inputFieldsWithValues);
......
......@@ -11,6 +11,7 @@ import dastSiteProfileUpdateMutation from 'ee/security_configuration/dast_site_p
import { siteProfiles } from 'ee_jest/on_demand_scans/mocks/mock_data';
import * as responses from 'ee_jest/security_configuration/dast_site_profiles_form/mock_data/apollo_mock';
import { TEST_HOST } from 'helpers/test_constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import * as urlUtility from '~/lib/utils/url_utility';
......@@ -44,24 +45,33 @@ describe('DastSiteProfileForm', () => {
const withinComponent = () => within(wrapper.element);
const findForm = () => wrapper.find(GlForm);
const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`);
const findProfileNameInput = () => findByTestId('profile-name-input');
const findTargetUrlInput = () => findByTestId('target-url-input');
const findAuthSection = () => wrapper.find(DastSiteAuthSection);
const findExcludedUrlsInput = () => findByTestId('excluded-urls-input');
const findRequestHeadersInput = () => findByTestId('request-headers-input');
const findSubmitButton = () => findByTestId('dast-site-profile-form-submit-button');
const findCancelButton = () => findByTestId('dast-site-profile-form-cancel-button');
const findCancelModal = () => wrapper.find(GlModal);
const findForm = () => wrapper.findComponent(GlForm);
const findAuthSection = () => wrapper.findComponent(DastSiteAuthSection);
const findCancelModal = () => wrapper.findComponent(GlModal);
const findByNameAttribute = (name) => wrapper.find(`[name="${name}"]`);
const findProfileNameInput = () => wrapper.findByTestId('profile-name-input');
const findTargetUrlInput = () => wrapper.findByTestId('target-url-input');
const findExcludedUrlsInput = () => wrapper.findByTestId('excluded-urls-input');
const findRequestHeadersInput = () => wrapper.findByTestId('request-headers-input');
const findAuthCheckbox = () => wrapper.findByTestId('auth-enable-checkbox');
const findSubmitButton = () => wrapper.findByTestId('dast-site-profile-form-submit-button');
const findCancelButton = () => wrapper.findByTestId('dast-site-profile-form-cancel-button');
const findAlert = () => wrapper.findByTestId('dast-site-profile-form-alert');
const submitForm = () => findForm().vm.$emit('submit', { preventDefault: () => {} });
const findAlert = () => findByTestId('dast-site-profile-form-alert');
const setFieldValue = async (field, value) => {
await field.setValue(value);
field.trigger('blur');
};
const setAuthFieldsValues = async ({ enabled, ...fields }) => {
await findAuthCheckbox().setChecked(enabled);
Object.keys(fields).forEach((field) => {
findByNameAttribute(field).setValue(fields[field]);
});
};
const mockClientFactory = (handlers) => {
const mockClient = createMockClient();
......@@ -109,7 +119,7 @@ describe('DastSiteProfileForm', () => {
},
);
wrapper = mountFn(DastSiteProfileForm, mountOpts);
wrapper = extendedWrapper(mountFn(DastSiteProfileForm, mountOpts));
};
const createComponent = componentFactory();
const createFullComponent = componentFactory(mount);
......@@ -189,6 +199,7 @@ describe('DastSiteProfileForm', () => {
await setFieldValue(findTargetUrlInput(), targetUrl);
await setFieldValue(findExcludedUrlsInput(), excludedUrls);
await setFieldValue(findRequestHeadersInput(), requestHeaders);
await setAuthFieldsValues(siteProfileOne.auth);
submitForm();
};
......@@ -209,6 +220,7 @@ describe('DastSiteProfileForm', () => {
excludedUrls,
requestHeaders,
fullPath,
auth: siteProfileOne.auth,
...mutationVars,
},
});
......
......@@ -34819,6 +34819,9 @@ msgstr ""
msgid "[No reason]"
msgstr ""
msgid "[Unchanged]"
msgstr ""
msgid "`end_time` should not exceed one month after `start_time`"
msgstr ""
......
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