You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.3 KiB

  1. const Model = require('objection').Model
  2. const fs = require('fs-extra')
  3. const path = require('path')
  4. const _ = require('lodash')
  5. const yaml = require('js-yaml')
  6. const commonHelper = require('../helpers/common')
  7. /* global WIKI */
  8. /**
  9. * Authentication model
  10. */
  11. module.exports = class Authentication extends Model {
  12. static get tableName() { return 'authentication' }
  13. static get idColumn() { return 'key' }
  14. static get jsonSchema () {
  15. return {
  16. type: 'object',
  17. required: ['key', 'isEnabled'],
  18. properties: {
  19. key: {type: 'string'},
  20. isEnabled: {type: 'boolean'},
  21. config: {type: 'object'},
  22. selfRegistration: {type: 'boolean'},
  23. domainWhitelist: {type: 'object'},
  24. autoEnrollGroups: {type: 'object'}
  25. }
  26. }
  27. }
  28. static async getStrategies() {
  29. const strategies = await WIKI.models.authentication.query()
  30. return strategies.map(str => ({
  31. ...str,
  32. domainWhitelist: _.get(str.domainWhitelist, 'v', []),
  33. autoEnrollGroups: _.get(str.autoEnrollGroups, 'v', [])
  34. }))
  35. }
  36. static async refreshStrategiesFromDisk() {
  37. let trx
  38. try {
  39. const dbStrategies = await WIKI.models.authentication.query()
  40. // -> Fetch definitions from disk
  41. const authDirs = await fs.readdir(path.join(WIKI.SERVERPATH, 'modules/authentication'))
  42. let diskStrategies = []
  43. for (let dir of authDirs) {
  44. const def = await fs.readFile(path.join(WIKI.SERVERPATH, 'modules/authentication', dir, 'definition.yml'), 'utf8')
  45. diskStrategies.push(yaml.safeLoad(def))
  46. }
  47. WIKI.data.authentication = diskStrategies.map(strategy => ({
  48. ...strategy,
  49. props: commonHelper.parseModuleProps(strategy.props)
  50. }))
  51. let newStrategies = []
  52. for (let strategy of WIKI.data.authentication) {
  53. if (!_.some(dbStrategies, ['key', strategy.key])) {
  54. newStrategies.push({
  55. key: strategy.key,
  56. isEnabled: false,
  57. config: _.transform(strategy.props, (result, value, key) => {
  58. _.set(result, key, value.default)
  59. return result
  60. }, {}),
  61. selfRegistration: false,
  62. domainWhitelist: { v: [] },
  63. autoEnrollGroups: { v: [] }
  64. })
  65. } else {
  66. const strategyConfig = _.get(_.find(dbStrategies, ['key', strategy.key]), 'config', {})
  67. await WIKI.models.authentication.query().patch({
  68. config: _.transform(strategy.props, (result, value, key) => {
  69. if (!_.has(result, key)) {
  70. _.set(result, key, value.default)
  71. }
  72. return result
  73. }, strategyConfig)
  74. }).where('key', strategy.key)
  75. }
  76. }
  77. if (newStrategies.length > 0) {
  78. trx = await WIKI.models.Objection.transaction.start(WIKI.models.knex)
  79. for (let strategy of newStrategies) {
  80. await WIKI.models.authentication.query(trx).insert(strategy)
  81. }
  82. await trx.commit()
  83. WIKI.logger.info(`Loaded ${newStrategies.length} new authentication strategies: [ OK ]`)
  84. } else {
  85. WIKI.logger.info(`No new authentication strategies found: [ SKIPPED ]`)
  86. }
  87. } catch (err) {
  88. WIKI.logger.error(`Failed to scan or load new authentication providers: [ FAILED ]`)
  89. WIKI.logger.error(err)
  90. if (trx) {
  91. trx.rollback()
  92. }
  93. }
  94. }
  95. }