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