1<template>
2  <b-container fluid="xl">
3    <page-title :description="$t('pageLdap.pageDescription')" />
4    <page-section :section-title="$t('pageLdap.settings')">
5      <b-form novalidate @submit.prevent="handleSubmit">
6        <b-row>
7          <b-col>
8            <b-form-group
9              class="mb-3"
10              :label="$t('pageLdap.form.ldapAuthentication')"
11              :disabled="loading"
12            >
13              <b-form-checkbox
14                v-model="form.ldapAuthenticationEnabled"
15                data-test-id="ldap-checkbox-ldapAuthenticationEnabled"
16                @change="onChangeldapAuthenticationEnabled"
17              >
18                {{ $t('global.action.enable') }}
19              </b-form-checkbox>
20            </b-form-group>
21          </b-col>
22        </b-row>
23        <div class="form-background p-3">
24          <b-form-group
25            class="m-0"
26            :label="$t('pageLdap.ariaLabel.ldapSettings')"
27            label-class="sr-only"
28            :disabled="!form.ldapAuthenticationEnabled || loading"
29          >
30            <b-row>
31              <b-col md="3" lg="4" xl="3">
32                <b-form-group
33                  class="mb-4"
34                  :label="$t('pageLdap.form.secureLdapUsingSsl')"
35                >
36                  <b-form-text id="enable-secure-help-block">
37                    {{ $t('pageLdap.form.secureLdapHelper') }}
38                  </b-form-text>
39                  <b-form-checkbox
40                    id="enable-secure-ldap"
41                    v-model="form.secureLdapEnabled"
42                    aria-describedby="enable-secure-help-block"
43                    data-test-id="ldap-checkbox-secureLdapEnabled"
44                    :disabled="
45                      !caCertificateExpiration || !ldapCertificateExpiration
46                    "
47                    @change="$v.form.secureLdapEnabled.$touch()"
48                  >
49                    {{ $t('global.action.enable') }}
50                  </b-form-checkbox>
51                </b-form-group>
52                <dl>
53                  <dt>{{ $t('pageLdap.form.caCertificateValidUntil') }}</dt>
54                  <dd v-if="caCertificateExpiration">
55                    {{ caCertificateExpiration | formatDate }}
56                  </dd>
57                  <dd v-else>--</dd>
58                  <dt>{{ $t('pageLdap.form.ldapCertificateValidUntil') }}</dt>
59                  <dd v-if="ldapCertificateExpiration">
60                    {{ ldapCertificateExpiration | formatDate }}
61                  </dd>
62                  <dd v-else>--</dd>
63                </dl>
64                <b-link
65                  class="d-inline-block mb-4 m-md-0"
66                  to="/security-and-access/certificates"
67                >
68                  {{ $t('pageLdap.form.manageSslCertificates') }}
69                </b-link>
70              </b-col>
71              <b-col md="9" lg="8" xl="9">
72                <b-row>
73                  <b-col>
74                    <b-form-group :label="$t('pageLdap.form.serviceType')">
75                      <b-form-radio
76                        v-model="form.activeDirectoryEnabled"
77                        data-test-id="ldap-radio-activeDirectoryEnabled"
78                        :value="false"
79                        @change="onChangeServiceType"
80                      >
81                        {{ $t('pageLdap.form.openLDAP') }}
82                      </b-form-radio>
83                      <b-form-radio
84                        v-model="form.activeDirectoryEnabled"
85                        data-test-id="ldap-radio-activeDirectoryEnabled"
86                        :value="true"
87                        @change="onChangeServiceType"
88                      >
89                        {{ $t('pageLdap.form.activeDirectory') }}
90                      </b-form-radio>
91                    </b-form-group>
92                  </b-col>
93                </b-row>
94                <b-row>
95                  <b-col sm="6" xl="4">
96                    <b-form-group label-for="server-uri">
97                      <template #label>
98                        {{ $t('pageLdap.form.serverUri') }}
99                        <info-tooltip
100                          :title="$t('pageLdap.form.serverUriTooltip')"
101                        />
102                      </template>
103                      <b-input-group :prepend="ldapProtocol">
104                        <b-form-input
105                          id="server-uri"
106                          v-model="form.serverUri"
107                          data-test-id="ldap-input-serverUri"
108                          :state="getValidationState($v.form.serverUri)"
109                          @change="$v.form.serverUri.$touch()"
110                        />
111                        <b-form-invalid-feedback role="alert">
112                          {{ $t('global.form.fieldRequired') }}
113                        </b-form-invalid-feedback>
114                      </b-input-group>
115                    </b-form-group>
116                  </b-col>
117                  <b-col sm="6" xl="4">
118                    <b-form-group
119                      :label="$t('pageLdap.form.bindDn')"
120                      label-for="bind-dn"
121                    >
122                      <b-form-input
123                        id="bind-dn"
124                        v-model="form.bindDn"
125                        data-test-id="ldap-input-bindDn"
126                        :state="getValidationState($v.form.bindDn)"
127                        @change="$v.form.bindDn.$touch()"
128                      />
129                      <b-form-invalid-feedback role="alert">
130                        {{ $t('global.form.fieldRequired') }}
131                      </b-form-invalid-feedback>
132                    </b-form-group>
133                  </b-col>
134                  <b-col sm="6" xl="4">
135                    <b-form-group
136                      :label="$t('pageLdap.form.bindPassword')"
137                      label-for="bind-password"
138                    >
139                      <input-password-toggle
140                        data-test-id="ldap-input-togglePassword"
141                      >
142                        <b-form-input
143                          id="bind-password"
144                          v-model="form.bindPassword"
145                          type="password"
146                          :state="getValidationState($v.form.bindPassword)"
147                          class="form-control-with-button"
148                          @change="$v.form.bindPassword.$touch()"
149                        />
150                        <b-form-invalid-feedback role="alert">
151                          {{ $t('global.form.fieldRequired') }}
152                        </b-form-invalid-feedback>
153                      </input-password-toggle>
154                    </b-form-group>
155                  </b-col>
156                  <b-col sm="6" xl="4">
157                    <b-form-group
158                      :label="$t('pageLdap.form.baseDn')"
159                      label-for="base-dn"
160                    >
161                      <b-form-input
162                        id="base-dn"
163                        v-model="form.baseDn"
164                        data-test-id="ldap-input-baseDn"
165                        :state="getValidationState($v.form.baseDn)"
166                        @change="$v.form.baseDn.$touch()"
167                      />
168                      <b-form-invalid-feedback role="alert">
169                        {{ $t('global.form.fieldRequired') }}
170                      </b-form-invalid-feedback>
171                    </b-form-group>
172                  </b-col>
173                  <b-col sm="6" xl="4">
174                    <b-form-group label-for="user-id-attribute">
175                      <template #label>
176                        {{ $t('pageLdap.form.userIdAttribute') }} -
177                        <span class="form-text d-inline">
178                          {{ $t('global.form.optional') }}
179                        </span>
180                      </template>
181                      <b-form-input
182                        id="user-id-attribute"
183                        v-model="form.userIdAttribute"
184                        data-test-id="ldap-input-userIdAttribute"
185                        @change="$v.form.userIdAttribute.$touch()"
186                      />
187                    </b-form-group>
188                  </b-col>
189                  <b-col sm="6" xl="4">
190                    <b-form-group label-for="group-id-attribute">
191                      <template #label>
192                        {{ $t('pageLdap.form.groupIdAttribute') }} -
193                        <span class="form-text d-inline">
194                          {{ $t('global.form.optional') }}
195                        </span>
196                      </template>
197                      <b-form-input
198                        id="group-id-attribute"
199                        v-model="form.groupIdAttribute"
200                        data-test-id="ldap-input-groupIdAttribute"
201                        @change="$v.form.groupIdAttribute.$touch()"
202                      />
203                    </b-form-group>
204                  </b-col>
205                </b-row>
206              </b-col>
207            </b-row>
208          </b-form-group>
209        </div>
210        <b-row class="mt-4 mb-5">
211          <b-col>
212            <b-btn
213              variant="primary"
214              type="submit"
215              data-test-id="ldap-button-saveSettings"
216              :disabled="loading"
217            >
218              {{ $t('global.action.saveSettings') }}
219            </b-btn>
220          </b-col>
221        </b-row>
222      </b-form>
223    </page-section>
224
225    <!-- Role groups -->
226    <page-section :section-title="$t('pageLdap.roleGroups')">
227      <table-role-groups />
228    </page-section>
229  </b-container>
230</template>
231
232<script>
233import { mapGetters } from 'vuex';
234import { find } from 'lodash';
235import { requiredIf } from 'vuelidate/lib/validators';
236
237import BVToastMixin from '@/components/Mixins/BVToastMixin';
238import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
239import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
240import InputPasswordToggle from '@/components/Global/InputPasswordToggle';
241import PageTitle from '@/components/Global/PageTitle';
242import PageSection from '@/components/Global/PageSection';
243import InfoTooltip from '@/components/Global/InfoTooltip';
244import TableRoleGroups from './TableRoleGroups';
245
246export default {
247  name: 'Ldap',
248  components: {
249    InfoTooltip,
250    InputPasswordToggle,
251    PageTitle,
252    PageSection,
253    TableRoleGroups,
254  },
255  mixins: [BVToastMixin, VuelidateMixin, LoadingBarMixin],
256  beforeRouteLeave(to, from, next) {
257    this.hideLoader();
258    next();
259  },
260  data() {
261    return {
262      form: {
263        ldapAuthenticationEnabled: this.$store.getters['ldap/isServiceEnabled'],
264        secureLdapEnabled: false,
265        activeDirectoryEnabled:
266          this.$store.getters['ldap/isActiveDirectoryEnabled'],
267        serverUri: '',
268        bindDn: '',
269        bindPassword: '',
270        baseDn: '',
271        userIdAttribute: '',
272        groupIdAttribute: '',
273        loading,
274      },
275    };
276  },
277  computed: {
278    ...mapGetters('ldap', [
279      'isServiceEnabled',
280      'isActiveDirectoryEnabled',
281      'ldap',
282      'activeDirectory',
283    ]),
284    sslCertificates() {
285      return this.$store.getters['certificates/allCertificates'];
286    },
287    caCertificateExpiration() {
288      const caCertificate = find(this.sslCertificates, {
289        type: 'TrustStore Certificate',
290      });
291      if (caCertificate === undefined) return null;
292      return caCertificate.validUntil;
293    },
294    ldapCertificateExpiration() {
295      const ldapCertificate = find(this.sslCertificates, {
296        type: 'LDAP Certificate',
297      });
298      if (ldapCertificate === undefined) return null;
299      return ldapCertificate.validUntil;
300    },
301    ldapProtocol() {
302      return this.form.secureLdapEnabled ? 'ldaps://' : 'ldap://';
303    },
304  },
305  watch: {
306    isServiceEnabled: function (value) {
307      this.form.ldapAuthenticationEnabled = value;
308    },
309    isActiveDirectoryEnabled: function (value) {
310      this.form.activeDirectoryEnabled = value;
311      this.setFormValues();
312    },
313  },
314  validations: {
315    form: {
316      ldapAuthenticationEnabled: {},
317      secureLdapEnabled: {},
318      activeDirectoryEnabled: {
319        required: requiredIf(function () {
320          return this.form.ldapAuthenticationEnabled;
321        }),
322      },
323      serverUri: {
324        required: requiredIf(function () {
325          return this.form.ldapAuthenticationEnabled;
326        }),
327      },
328      bindDn: {
329        required: requiredIf(function () {
330          return this.form.ldapAuthenticationEnabled;
331        }),
332      },
333      bindPassword: {
334        required: requiredIf(function () {
335          return this.form.ldapAuthenticationEnabled;
336        }),
337      },
338      baseDn: {
339        required: requiredIf(function () {
340          return this.form.ldapAuthenticationEnabled;
341        }),
342      },
343      userIdAttribute: {},
344      groupIdAttribute: {},
345    },
346  },
347  created() {
348    this.startLoader();
349    this.$store
350      .dispatch('ldap/getAccountSettings')
351      .finally(() => this.endLoader());
352    this.$store
353      .dispatch('certificates/getCertificates')
354      .finally(() => this.endLoader());
355    this.setFormValues();
356  },
357  methods: {
358    setFormValues(serviceType) {
359      if (!serviceType) {
360        serviceType = this.isActiveDirectoryEnabled
361          ? this.activeDirectory
362          : this.ldap;
363      }
364      const {
365        serviceAddress = '',
366        bindDn = '',
367        baseDn = '',
368        userAttribute = '',
369        groupsAttribute = '',
370      } = serviceType;
371      const secureLdap =
372        serviceAddress && serviceAddress.includes('ldaps://') ? true : false;
373      const serverUri = serviceAddress
374        ? serviceAddress.replace(/ldaps?:\/\//, '')
375        : '';
376      this.form.secureLdapEnabled = secureLdap;
377      this.form.serverUri = serverUri;
378      this.form.bindDn = bindDn;
379      this.form.bindPassword = '';
380      this.form.baseDn = baseDn;
381      this.form.userIdAttribute = userAttribute;
382      this.form.groupIdAttribute = groupsAttribute;
383    },
384    handleSubmit() {
385      this.$v.$touch();
386      if (this.$v.$invalid) return;
387      const data = {
388        serviceEnabled: this.form.ldapAuthenticationEnabled,
389        activeDirectoryEnabled: this.form.activeDirectoryEnabled,
390        serviceAddress: `${this.ldapProtocol}${this.form.serverUri}`,
391        bindDn: this.form.bindDn,
392        bindPassword: this.form.bindPassword,
393        baseDn: this.form.baseDn,
394        userIdAttribute: this.form.userIdAttribute,
395        groupIdAttribute: this.form.groupIdAttribute,
396      };
397      this.startLoader();
398      this.$store
399        .dispatch('ldap/saveAccountSettings', data)
400        .then((success) => {
401          this.successToast(success);
402        })
403        .catch(({ message }) => {
404          this.errorToast(message);
405        })
406        .finally(() => {
407          this.form.bindPassword = '';
408          this.$v.form.$reset();
409          this.endLoader();
410        });
411    },
412    onChangeServiceType(isActiveDirectoryEnabled) {
413      this.$v.form.activeDirectoryEnabled.$touch();
414      const serviceType = isActiveDirectoryEnabled
415        ? this.activeDirectory
416        : this.ldap;
417      // Set form values according to user selected
418      // service type
419      this.setFormValues(serviceType);
420    },
421    onChangeldapAuthenticationEnabled(isServiceEnabled) {
422      this.$v.form.ldapAuthenticationEnabled.$touch();
423      if (!isServiceEnabled) {
424        // Request will fail if sent with empty values.
425        // The frontend only checks for required fields
426        // when the service is enabled. This is to prevent
427        // an error if a user clears any properties then
428        // disables the service.
429        this.setFormValues();
430      }
431    },
432  },
433};
434</script>
435