xref: /openbmc/webui-vue/src/views/SecurityAndAccess/Ldap/Ldap.vue (revision 7d6b44cb263da09e575c7cb28cab88c1eb339c7b)
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 }}
56                  </dd>
57                  <dd v-else>--</dd>
58                  <dt>{{ $t('pageLdap.form.ldapCertificateValidUntil') }}</dt>
59                  <dd v-if="ldapCertificateExpiration">
60                    {{ ldapCertificateExpiration }}
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/validators';
236import { useVuelidate } from '@vuelidate/core';
237
238import BVToastMixin from '@/components/Mixins/BVToastMixin';
239import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
240import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
241import InputPasswordToggle from '@/components/Global/InputPasswordToggle';
242import PageTitle from '@/components/Global/PageTitle';
243import PageSection from '@/components/Global/PageSection';
244import InfoTooltip from '@/components/Global/InfoTooltip';
245import TableRoleGroups from './TableRoleGroups';
246
247export default {
248  name: 'Ldap',
249  components: {
250    InfoTooltip,
251    InputPasswordToggle,
252    PageTitle,
253    PageSection,
254    TableRoleGroups,
255  },
256  mixins: [BVToastMixin, VuelidateMixin, LoadingBarMixin],
257  beforeRouteLeave(to, from, next) {
258    this.hideLoader();
259    next();
260  },
261  setup() {
262    return {
263      v$: useVuelidate(),
264    };
265  },
266  data() {
267    return {
268      form: {
269        ldapAuthenticationEnabled: this.$store.getters['ldap/isServiceEnabled'],
270        secureLdapEnabled: false,
271        activeDirectoryEnabled:
272          this.$store.getters['ldap/isActiveDirectoryEnabled'],
273        serverUri: '',
274        bindDn: '',
275        bindPassword: '',
276        baseDn: '',
277        userIdAttribute: '',
278        groupIdAttribute: '',
279        loading,
280      },
281    };
282  },
283  computed: {
284    ...mapGetters('ldap', [
285      'isServiceEnabled',
286      'isActiveDirectoryEnabled',
287      'ldap',
288      'activeDirectory',
289    ]),
290    sslCertificates() {
291      return this.$store.getters['certificates/allCertificates'];
292    },
293    caCertificateExpiration() {
294      const caCertificate = find(this.sslCertificates, {
295        type: 'TrustStore Certificate',
296      });
297      if (caCertificate === undefined) return null;
298      return caCertificate.validUntil;
299    },
300    ldapCertificateExpiration() {
301      const ldapCertificate = find(this.sslCertificates, {
302        type: 'LDAP Certificate',
303      });
304      if (ldapCertificate === undefined) return null;
305      return ldapCertificate.validUntil;
306    },
307    ldapProtocol() {
308      return this.form.secureLdapEnabled ? 'ldaps://' : 'ldap://';
309    },
310  },
311  watch: {
312    isServiceEnabled: function (value) {
313      this.form.ldapAuthenticationEnabled = value;
314    },
315    isActiveDirectoryEnabled: function (value) {
316      this.form.activeDirectoryEnabled = value;
317      this.setFormValues();
318    },
319  },
320  validations: {
321    form: {
322      ldapAuthenticationEnabled: {},
323      secureLdapEnabled: {},
324      activeDirectoryEnabled: {
325        required: requiredIf(function () {
326          return this.form.ldapAuthenticationEnabled;
327        }),
328      },
329      serverUri: {
330        required: requiredIf(function () {
331          return this.form.ldapAuthenticationEnabled;
332        }),
333      },
334      bindDn: {
335        required: requiredIf(function () {
336          return this.form.ldapAuthenticationEnabled;
337        }),
338      },
339      bindPassword: {
340        required: requiredIf(function () {
341          return this.form.ldapAuthenticationEnabled;
342        }),
343      },
344      baseDn: {
345        required: requiredIf(function () {
346          return this.form.ldapAuthenticationEnabled;
347        }),
348      },
349      userIdAttribute: {},
350      groupIdAttribute: {},
351    },
352  },
353  created() {
354    this.startLoader();
355    this.$store
356      .dispatch('ldap/getAccountSettings')
357      .finally(() => this.endLoader());
358    this.$store
359      .dispatch('certificates/getCertificates')
360      .finally(() => this.endLoader());
361    this.setFormValues();
362  },
363  methods: {
364    setFormValues(serviceType) {
365      if (!serviceType) {
366        serviceType = this.isActiveDirectoryEnabled
367          ? this.activeDirectory
368          : this.ldap;
369      }
370      const {
371        serviceAddress = '',
372        bindDn = '',
373        baseDn = '',
374        userAttribute = '',
375        groupsAttribute = '',
376      } = serviceType;
377      const secureLdap =
378        serviceAddress && serviceAddress.includes('ldaps://') ? true : false;
379      const serverUri = serviceAddress
380        ? serviceAddress.replace(/ldaps?:\/\//, '')
381        : '';
382      this.form.secureLdapEnabled = secureLdap;
383      this.form.serverUri = serverUri;
384      this.form.bindDn = bindDn;
385      this.form.bindPassword = '';
386      this.form.baseDn = baseDn;
387      this.form.userIdAttribute = userAttribute;
388      this.form.groupIdAttribute = groupsAttribute;
389    },
390    handleSubmit() {
391      this.$v.$touch();
392      if (this.$v.$invalid) return;
393      const data = {
394        serviceEnabled: this.form.ldapAuthenticationEnabled,
395        activeDirectoryEnabled: this.form.activeDirectoryEnabled,
396        serviceAddress: `${this.ldapProtocol}${this.form.serverUri}`,
397        bindDn: this.form.bindDn,
398        bindPassword: this.form.bindPassword,
399        baseDn: this.form.baseDn,
400        userIdAttribute: this.form.userIdAttribute,
401        groupIdAttribute: this.form.groupIdAttribute,
402      };
403      this.startLoader();
404      this.$store
405        .dispatch('ldap/saveAccountSettings', data)
406        .then((success) => {
407          this.successToast(success);
408        })
409        .catch(({ message }) => {
410          this.errorToast(message);
411        })
412        .finally(() => {
413          this.form.bindPassword = '';
414          this.$v.form.$reset();
415          this.endLoader();
416        });
417    },
418    onChangeServiceType(isActiveDirectoryEnabled) {
419      this.$v.form.activeDirectoryEnabled.$touch();
420      const serviceType = isActiveDirectoryEnabled
421        ? this.activeDirectory
422        : this.ldap;
423      // Set form values according to user selected
424      // service type
425      this.setFormValues(serviceType);
426    },
427    onChangeldapAuthenticationEnabled(isServiceEnabled) {
428      this.$v.form.ldapAuthenticationEnabled.$touch();
429      if (!isServiceEnabled) {
430        // Request will fail if sent with empty values.
431        // The frontend only checks for required fields
432        // when the service is enabled. This is to prevent
433        // an error if a user clears any properties then
434        // disables the service.
435        this.setFormValues();
436      }
437    },
438  },
439};
440</script>
441