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