feat: auth self-registration config + gql grouping
This commit is contained in:
1 parent
49834461a6
commit
0afa65fa58
39 files changed
+104
-50
No files matched your search
@@ -9,7 +9,8 @@
|
||||
|
||||
v-tab-item(key='settings', :transition='false', :reverse-transition='false')
|
||||
v-card.pa-3(flat, tile)
|
||||
v-subheader.pl-0.pb-2 Select which authentication strategies to enable:
|
||||
.body-2.grey--text.text--darken-1 Select which authentication strategies to enable:
|
||||
.caption.grey--text.pb-2 Some strategies require additional configuration in their dedicated tab (when selected).
|
||||
v-form
|
||||
v-checkbox(
|
||||
v-for='strategy in strategies',
|
||||
@@ -27,19 +28,36 @@
|
||||
v-form
|
||||
v-subheader.pl-0 Strategy Configuration
|
||||
.body-1.ml-3(v-if='!strategy.config || strategy.config.length < 1') This strategy has no configuration options you can modify.
|
||||
v-text-field(v-else, v-for='cfg in strategy.config', :key='cfg.key', :label='cfg.key', prepend-icon='settings_applications')
|
||||
v-text-field(
|
||||
v-else
|
||||
v-for='cfg in strategy.config'
|
||||
:key='cfg.key'
|
||||
:label='cfg.key'
|
||||
v-model='cfg.value'
|
||||
prepend-icon='settings_applications'
|
||||
)
|
||||
v-divider
|
||||
v-subheader.pl-0 Registration
|
||||
v-switch.ml-3(
|
||||
v-model='auths',
|
||||
v-model='allowSelfRegistration',
|
||||
label='Allow self-registration',
|
||||
:value='true',
|
||||
color='primary',
|
||||
hint='Allow any user successfully authorized by the strategy to access the wiki.',
|
||||
persistent-hint
|
||||
)
|
||||
v-text-field.ml-3(label='Limit to specific email domains', prepend-icon='mail_outline')
|
||||
v-text-field.ml-3(label='Assign to group', prepend-icon='people')
|
||||
v-text-field.ml-3(
|
||||
label='Limit to specific email domains'
|
||||
prepend-icon='mail_outline'
|
||||
hint='Domain(s) seperated by comma. (e.g. domain1.com, domain2.com)'
|
||||
persistent-hint
|
||||
)
|
||||
v-text-field.ml-3(
|
||||
label='Assign to group'
|
||||
prepend-icon='people'
|
||||
hint='Automatically assign new users to these groups.'
|
||||
persistent-hint
|
||||
)
|
||||
|
||||
v-card-chin
|
||||
v-btn(color='primary')
|
||||
@@ -54,14 +72,17 @@
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
|
||||
import strategiesQuery from 'gql/admin-auth-query-strategies.gql'
|
||||
import strategiesSaveMutation from 'gql/admin-auth-mutation-save-strategies.gql'
|
||||
import strategiesQuery from 'gql/admin/auth/auth-query-strategies.gql'
|
||||
import strategiesSaveMutation from 'gql/admin/auth/auth-mutation-save-strategies.gql'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
strategies: [],
|
||||
selectedStrategies: ['local']
|
||||
selectedStrategies: ['local'],
|
||||
selfRegistration: false,
|
||||
domainWhitelist: [],
|
||||
autoEnrollGroups: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -114,11 +114,11 @@
|
||||
import Criterias from '../common/criterias.vue'
|
||||
import UserSearch from '../common/user-search.vue'
|
||||
|
||||
import groupQuery from 'gql/admin-groups-query-single.gql'
|
||||
import assignUserMutation from 'gql/admin-groups-mutation-assign.gql'
|
||||
import deleteGroupMutation from 'gql/admin-groups-mutation-delete.gql'
|
||||
import unassignUserMutation from 'gql/admin-groups-mutation-unassign.gql'
|
||||
import updateGroupMutation from 'gql/admin-groups-mutation-update.gql'
|
||||
import groupQuery from 'gql/admin/groups/groups-query-single.gql'
|
||||
import assignUserMutation from 'gql/admin/groups/groups-mutation-assign.gql'
|
||||
import deleteGroupMutation from 'gql/admin/groups/groups-mutation-delete.gql'
|
||||
import unassignUserMutation from 'gql/admin/groups/groups-mutation-unassign.gql'
|
||||
import updateGroupMutation from 'gql/admin/groups/groups-mutation-update.gql'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
.dialog-header.is-short New Group
|
||||
v-card-text
|
||||
v-text-field(v-model='newGroupName', label='Group Name', autofocus, counter='255', @keyup.enter='createGroup')
|
||||
v-card-actions
|
||||
v-card-chin
|
||||
v-spacer
|
||||
v-btn(flat, @click='newGroupDialog = false') Cancel
|
||||
v-btn(color='primary', @click='createGroup') Create
|
||||
@@ -45,9 +45,9 @@
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
|
||||
import groupsQuery from 'gql/admin-groups-query-list.gql'
|
||||
import createGroupMutation from 'gql/admin-groups-mutation-create.gql'
|
||||
import deleteGroupMutation from 'gql/admin-groups-mutation-delete.gql'
|
||||
import groupsQuery from 'gql/admin/groups/groups-query-list.gql'
|
||||
import createGroupMutation from 'gql/admin/groups/groups-mutation-create.gql'
|
||||
import deleteGroupMutation from 'gql/admin/groups/groups-mutation-delete.gql'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
||||
@@ -128,9 +128,9 @@ import _ from 'lodash'
|
||||
|
||||
/* global WIKI */
|
||||
|
||||
import localesQuery from 'gql/admin-locale-query-list.gql'
|
||||
import localesDownloadMutation from 'gql/admin-locale-mutation-download.gql'
|
||||
import localesSaveMutation from 'gql/admin-locale-mutation-save.gql'
|
||||
import localesQuery from 'gql/admin/locale/locale-query-list.gql'
|
||||
import localesDownloadMutation from 'gql/admin/locale/locale-mutation-download.gql'
|
||||
import localesSaveMutation from 'gql/admin/locale/locale-mutation-save.gql'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
||||
@@ -106,7 +106,7 @@ import IconCube from 'mdi/cube'
|
||||
import IconDatabase from 'mdi/database'
|
||||
import IconNodeJs from 'mdi/nodejs'
|
||||
|
||||
import systemInfoQuery from 'gql/admin-system-query-info.gql'
|
||||
import systemInfoQuery from 'gql/admin/system/system-query-info.gql'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
|
||||
import themeSaveMutation from 'gql/admin-theme-mutation-save.gql'
|
||||
import themeSaveMutation from 'gql/admin/theme/theme-mutation-save.gql'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
|
||||
import searchUsersQuery from 'gql/common-users-query-search.gql'
|
||||
import searchUsersQuery from 'gql/common/common-users-query-search.gql'
|
||||
|
||||
export default {
|
||||
filters: {
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
import _ from 'lodash'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
import strategiesQuery from 'gql/login-query-strategies.gql'
|
||||
import loginMutation from 'gql/login-mutation-login.gql'
|
||||
import tfaMutation from 'gql/login-mutation-tfa.gql'
|
||||
import strategiesQuery from 'gql/login/login-query-strategies.gql'
|
||||
import loginMutation from 'gql/login/login-mutation-login.gql'
|
||||
import tfaMutation from 'gql/login/login-mutation-tfa.gql'
|
||||
|
||||
export default {
|
||||
i18nOptions: { namespaces: 'auth' },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template lang='pug'>
|
||||
v-app.profile
|
||||
v-app(:dark='darkMode').profile
|
||||
nav-header
|
||||
v-navigation-drawer.pb-0(v-model='profileDrawerShown', app, fixed, clipped, left, permanent)
|
||||
v-list(dense)
|
||||
@@ -22,7 +22,7 @@
|
||||
transition(name='profile-router')
|
||||
router-view
|
||||
|
||||
v-footer.py-2.justify-center(app, absolute, color='grey lighten-3', inset, height='auto')
|
||||
v-footer.py-2.justify-center(app, absolute, :color='darkMode ? "" : "grey lighten-3"', inset, height='auto')
|
||||
.caption.grey--text.text--darken-1 Powered by Wiki.js
|
||||
|
||||
v-snackbar(
|
||||
@@ -41,7 +41,7 @@
|
||||
import VueRouter from 'vue-router'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/* global WIKI */
|
||||
/* global WIKI, siteConfig */
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
@@ -75,7 +75,8 @@ export default {
|
||||
notificationState: {
|
||||
get() { return this.notification.isActive },
|
||||
set(newState) { this.$store.commit('updateNotificationState', newState) }
|
||||
}
|
||||
},
|
||||
darkMode() { return siteConfig.darkMode }
|
||||
},
|
||||
router
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
v-divider
|
||||
v-subheader.pl-0 Timezone
|
||||
v-select.grey.lighten-5(solo, flat)
|
||||
v-divider.my-0
|
||||
v-card-actions.grey.lighten-4
|
||||
v-card-chin
|
||||
v-spacer
|
||||
v-btn(color='primary')
|
||||
v-icon(left) chevron_right
|
||||
@@ -32,8 +31,7 @@
|
||||
v-card-text
|
||||
v-subheader.pl-0 Default Editor
|
||||
v-select.grey.lighten-5(solo, flat)
|
||||
v-divider.my-0
|
||||
v-card-actions.grey.lighten-4
|
||||
v-card-chin
|
||||
v-spacer
|
||||
v-btn(color='primary')
|
||||
v-icon(left) chevron_right
|
||||
@@ -42,10 +40,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global siteConfig */
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return { }
|
||||
},
|
||||
computed: {
|
||||
darkMode() { return siteConfig.darkMode }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
v-text-field(label='Name', :counter='255', v-model='name', prepend-icon='person')
|
||||
v-text-field(label='Job Title', :counter='255', prepend-icon='accessibility')
|
||||
v-text-field(label='Location / Office', :counter='255', prepend-icon='location_on')
|
||||
v-divider.my-0
|
||||
v-card-actions.grey.lighten-4
|
||||
v-card-chin
|
||||
v-spacer
|
||||
v-btn(color='primary')
|
||||
v-icon(left) chevron_right
|
||||
@@ -29,8 +28,13 @@
|
||||
.subheading Authentication
|
||||
v-card-text
|
||||
v-subheader.pl-0 Provider
|
||||
v-toolbar(flat, color='purple lighten-5', dense).purple--text.text--darken-4
|
||||
v-icon(color='purple darken-4') supervised_user_circle
|
||||
v-toolbar(
|
||||
flat
|
||||
:color='darkMode ? "grey darken-2" : "purple lighten-5"'
|
||||
dense
|
||||
:class='darkMode ? "grey--text text--lighten-1" : "purple--text text--darken-4"'
|
||||
)
|
||||
v-icon(:color='darkMode ? "grey lighten-1" : "purple darken-4"') supervised_user_circle
|
||||
.subheading.ml-3 Local
|
||||
v-divider
|
||||
v-subheader.pl-0 Two-Factor Authentication (2FA)
|
||||
@@ -72,12 +76,16 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global siteConfig */
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
name: 'John Doe'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
darkMode() { return siteConfig.darkMode }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
File renamed without changes.
+4
-1
@@ -1,6 +1,6 @@
|
||||
query {
|
||||
authentication {
|
||||
strategies {
|
||||
strategies(orderBy: "title ASC") {
|
||||
isEnabled
|
||||
key
|
||||
props
|
||||
@@ -10,6 +10,9 @@ query {
|
||||
key
|
||||
value
|
||||
}
|
||||
selfRegistration
|
||||
domainWhitelist
|
||||
autoEnrollGroups
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -6,7 +6,7 @@ import _ from 'lodash'
|
||||
|
||||
/* global siteConfig, graphQL */
|
||||
|
||||
import localeQuery from 'gql/common-locale-query.gql'
|
||||
import localeQuery from 'gql/common/common-locale-query.gql'
|
||||
|
||||
module.exports = {
|
||||
VueI18Next,
|
||||
|
||||
+5
-3
@@ -39,12 +39,14 @@ module.exports = {
|
||||
_.pull(currentStrategies, 'session')
|
||||
_.forEach(currentStrategies, stg => { passport.unuse(stg) })
|
||||
|
||||
// Load enable strategies
|
||||
const enabledStrategies = await WIKI.db.authentication.getEnabledStrategies()
|
||||
console.info(enabledStrategies)
|
||||
// Load enabled strategies
|
||||
const enabledStrategies = await WIKI.db.authentication.getStrategies()
|
||||
for (let idx in enabledStrategies) {
|
||||
const stg = enabledStrategies[idx]
|
||||
if (!stg.isEnabled) { continue }
|
||||
|
||||
const strategy = require(`../modules/authentication/${stg.key}`)
|
||||
|
||||
stg.config.callbackURL = `${WIKI.config.host}/login/${stg.key}/callback` // TODO: config.host
|
||||
strategy.init(passport, stg.config)
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ exports.up = knex => {
|
||||
table.boolean('isEnabled').notNullable().defaultTo(false)
|
||||
table.boolean('useForm').notNullable().defaultTo(false)
|
||||
table.jsonb('config').notNullable()
|
||||
table.boolean('selfRegistration').notNullable().defaultTo(false)
|
||||
table.jsonb('domainWhitelist').notNullable()
|
||||
table.jsonb('autoEnrollGroups').notNullable()
|
||||
})
|
||||
// COMMENTS ----------------------------
|
||||
.createTable('comments', table => {
|
||||
|
||||
@@ -22,13 +22,21 @@ module.exports = class Authentication extends Model {
|
||||
title: {type: 'string'},
|
||||
isEnabled: {type: 'boolean'},
|
||||
useForm: {type: 'boolean'},
|
||||
config: {type: 'object'}
|
||||
config: {type: 'object'},
|
||||
selfRegistration: {type: 'boolean'},
|
||||
domainWhitelist: {type: 'object'},
|
||||
autoEnrollGroups: {type: 'object'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async getEnabledStrategies() {
|
||||
return WIKI.db.authentication.query().where({ isEnabled: true })
|
||||
static async getStrategies() {
|
||||
const strategies = await WIKI.db.authentication.query()
|
||||
return strategies.map(str => ({
|
||||
...str,
|
||||
domainWhitelist: _.get(str.domainWhitelist, 'v', []),
|
||||
autoEnrollGroups: _.get(str.autoEnrollGroups, 'v', [])
|
||||
}))
|
||||
}
|
||||
|
||||
static async refreshStrategiesFromDisk() {
|
||||
@@ -46,7 +54,10 @@ module.exports = class Authentication extends Model {
|
||||
config: _.reduce(strategy.props, (result, value, key) => {
|
||||
_.set(result, value, '')
|
||||
return result
|
||||
}, {})
|
||||
}, {}),
|
||||
selfRegistration: false,
|
||||
domainWhitelist: { v: [] },
|
||||
autoEnrollGroups: { v: [] }
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,7 +16,7 @@ module.exports = {
|
||||
},
|
||||
AuthenticationQuery: {
|
||||
async strategies(obj, args, context, info) {
|
||||
let strategies = await WIKI.db.authentication.getEnabledStrategies()
|
||||
let strategies = await WIKI.db.authentication.getStrategies()
|
||||
strategies = strategies.map(stg => ({
|
||||
...stg,
|
||||
config: _.transform(stg.config, (res, value, key) => {
|
||||
|
||||
@@ -56,6 +56,9 @@ type AuthenticationStrategy {
|
||||
useForm: Boolean!
|
||||
icon: String
|
||||
config: [KeyValuePair]
|
||||
selfRegistration: Boolean!
|
||||
domainWhitelist: [String]!
|
||||
autoEnrollGroups: [String]!
|
||||
}
|
||||
|
||||
type AuthenticationLoginResponse {
|
||||
|
||||
@@ -24,7 +24,7 @@ module.exports = {
|
||||
return arr.filter(prvFilter.test)
|
||||
},
|
||||
orderBy (arr, orderString) {
|
||||
let orderParams = _.zip(orderString.split(',').map(ord => _.trim(ord).split(' ').map(_.trim)))
|
||||
let orderParams = _.zip(...orderString.split(',').map(ord => _.trim(ord).split(' ').map(_.trim)))
|
||||
return _.orderBy(arr, orderParams[0], orderParams[1])
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ const GoogleStrategy = require('passport-google-oauth20').Strategy
|
||||
|
||||
module.exports = {
|
||||
key: 'google',
|
||||
title: 'Google ID',
|
||||
title: 'Google',
|
||||
useForm: false,
|
||||
props: ['clientId', 'clientSecret'],
|
||||
init (passport, conf) {
|
||||
|
||||
Reference in new issue
Block a user