AdminTwoFactor.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <template>
  2. <div>
  3. <p class="settings-hint">
  4. {{ t('settings', 'Two-factor authentication can be enforced for all users and specific groups. If they do not have a two-factor provider configured, they will be unable to log into the system.') }}
  5. </p>
  6. <p v-if="loading">
  7. <span class="icon-loading-small two-factor-loading" />
  8. <span>{{ t('settings', 'Enforce two-factor authentication') }}</span>
  9. </p>
  10. <p v-else>
  11. <input id="two-factor-enforced"
  12. v-model="enforced"
  13. type="checkbox"
  14. class="checkbox">
  15. <label for="two-factor-enforced">{{ t('settings', 'Enforce two-factor authentication') }}</label>
  16. </p>
  17. <template v-if="enforced">
  18. <h3>{{ t('settings', 'Limit to groups') }}</h3>
  19. {{ t('settings', 'Enforcement of two-factor authentication can be set for certain groups only.') }}
  20. <p>
  21. {{ t('settings', 'Two-factor authentication is enforced for all members of the following groups.') }}
  22. </p>
  23. <p>
  24. <Multiselect v-model="enforcedGroups"
  25. :options="groups"
  26. :placeholder="t('settings', 'Enforced groups')"
  27. :disabled="loading"
  28. :multiple="true"
  29. :searchable="true"
  30. :loading="loadingGroups"
  31. :show-no-options="false"
  32. :close-on-select="false"
  33. @search-change="searchGroup" />
  34. </p>
  35. <p>
  36. {{ t('settings', 'Two-factor authentication is not enforced for members of the following groups.') }}
  37. </p>
  38. <p>
  39. <Multiselect v-model="excludedGroups"
  40. :options="groups"
  41. :placeholder="t('settings', 'Excluded groups')"
  42. :disabled="loading"
  43. :multiple="true"
  44. :searchable="true"
  45. :loading="loadingGroups"
  46. :show-no-options="false"
  47. :close-on-select="false"
  48. @search-change="searchGroup" />
  49. </p>
  50. <p>
  51. <em>
  52. <!-- this text is also found in the documentation. update it there as well if it ever changes -->
  53. {{ t('settings', 'When groups are selected/excluded, they use the following logic to determine if a user has 2FA enforced: If no groups are selected, 2FA is enabled for everyone except members of the excluded groups. If groups are selected, 2FA is enabled for all members of these. If a user is both in a selected and excluded group, the selected takes precedence and 2FA is enforced.') }}
  54. </em>
  55. </p>
  56. </template>
  57. <p>
  58. <button v-if="dirty"
  59. class="button primary"
  60. :disabled="loading"
  61. @click="saveChanges">
  62. {{ t('settings', 'Save changes') }}
  63. </button>
  64. </p>
  65. </div>
  66. </template>
  67. <script>
  68. import axios from '@nextcloud/axios'
  69. import { Multiselect } from 'nextcloud-vue'
  70. import _ from 'lodash'
  71. export default {
  72. name: 'AdminTwoFactor',
  73. components: {
  74. Multiselect,
  75. },
  76. data() {
  77. return {
  78. loading: false,
  79. dirty: false,
  80. groups: [],
  81. loadingGroups: false,
  82. }
  83. },
  84. computed: {
  85. enforced: {
  86. get: function() {
  87. return this.$store.state.enforced
  88. },
  89. set: function(val) {
  90. this.dirty = true
  91. this.$store.commit('setEnforced', val)
  92. },
  93. },
  94. enforcedGroups: {
  95. get: function() {
  96. return this.$store.state.enforcedGroups
  97. },
  98. set: function(val) {
  99. this.dirty = true
  100. this.$store.commit('setEnforcedGroups', val)
  101. },
  102. },
  103. excludedGroups: {
  104. get: function() {
  105. return this.$store.state.excludedGroups
  106. },
  107. set: function(val) {
  108. this.dirty = true
  109. this.$store.commit('setExcludedGroups', val)
  110. },
  111. },
  112. },
  113. mounted() {
  114. // Groups are loaded dynamically, but the assigned ones *should*
  115. // be valid groups, so let's add them as initial state
  116. this.groups = _.sortedUniq(_.uniq(this.enforcedGroups.concat(this.excludedGroups)))
  117. // Populate the groups with a first set so the dropdown is not empty
  118. // when opening the page the first time
  119. this.searchGroup('')
  120. },
  121. methods: {
  122. searchGroup: _.debounce(function(query) {
  123. this.loadingGroups = true
  124. axios.get(OC.linkToOCS(`cloud/groups?offset=0&search=${encodeURIComponent(query)}&limit=20`, 2))
  125. .then(res => res.data.ocs)
  126. .then(ocs => ocs.data.groups)
  127. .then(groups => { this.groups = _.sortedUniq(_.uniq(this.groups.concat(groups))) })
  128. .catch(err => console.error('could not search groups', err))
  129. .then(() => { this.loadingGroups = false })
  130. }, 500),
  131. saveChanges() {
  132. this.loading = true
  133. const data = {
  134. enforced: this.enforced,
  135. enforcedGroups: this.enforcedGroups,
  136. excludedGroups: this.excludedGroups,
  137. }
  138. axios.put(OC.generateUrl('/settings/api/admin/twofactorauth'), data)
  139. .then(resp => resp.data)
  140. .then(state => {
  141. this.state = state
  142. this.dirty = false
  143. })
  144. .catch(err => {
  145. console.error('could not save changes', err)
  146. })
  147. .then(() => { this.loading = false })
  148. },
  149. },
  150. }
  151. </script>
  152. <style>
  153. .two-factor-loading {
  154. display: inline-block;
  155. vertical-align: sub;
  156. margin-left: -2px;
  157. margin-right: 1px;
  158. }
  159. </style>