浏览代码

feat: ldap module + deps upgrade

Nick 6 年之前
父节点
当前提交
26c7d49a78

+ 1 - 0
client/components/admin/admin-general.vue

@@ -168,6 +168,7 @@ export default {
     return {
       analyticsServices: [
         { text: 'None', value: '' },
+        { text: 'Elasticsearch APM', value: 'elk' },
         { text: 'Google Analytics', value: 'ga' },
         { text: 'Google Tag Manager', value: 'gtm' }
       ],

+ 1 - 1
client/components/login.vue

@@ -15,7 +15,7 @@
                 v-toolbar(color='primary', flat, dense, dark)
                   v-spacer
                   .subheading(v-if='screen === "tfa"') {{ $t('auth:tfa.subtitle') }}
-                  .subheading(v-else-if='selectedStrategy.key !== "local"') {{ $t('auth:loginUsingStrategy', { strategy: selectedStrategy.title }) }}
+                  .subheading(v-else-if='selectedStrategy.key !== "local"') {{ $t('auth:loginUsingStrategy', { strategy: selectedStrategy.title, interpolation: { escapeValue: false } }) }}
                   .subheading(v-else) {{ $t('auth:loginRequired') }}
                   v-spacer
                 v-card-text.text-xs-center

+ 107 - 107
package.json

@@ -40,24 +40,24 @@
   },
   "dependencies": {
     "@aoberoi/passport-slack": "1.0.5",
-    "@bugsnag/js": "5.2.0",
+    "@bugsnag/js": "6.2.0",
     "algoliasearch": "3.32.1",
     "apollo-fetch": "0.7.0",
-    "apollo-server": "2.3.3",
-    "apollo-server-express": "2.3.3",
+    "apollo-server": "2.4.8",
+    "apollo-server-express": "2.4.8",
     "auto-load": "3.0.4",
-    "aws-sdk": "2.420.0",
+    "aws-sdk": "2.444.0",
     "axios": "0.18.0",
     "azure-search-client": "3.1.5",
     "bcryptjs-then": "1.0.1",
-    "bluebird": "3.5.3",
-    "body-parser": "1.18.3",
+    "bluebird": "3.5.4",
+    "body-parser": "1.19.0",
     "chalk": "2.4.2",
-    "cheerio": "1.0.0-rc.2",
-    "chokidar": "2.0.4",
+    "cheerio": "1.0.0-rc.3",
+    "chokidar": "2.1.5",
     "clean-css": "4.2.1",
-    "compression": "1.7.3",
-    "cookie-parser": "1.4.3",
+    "compression": "1.7.4",
+    "cookie-parser": "1.4.4",
     "cors": "2.8.5",
     "custom-error-instance": "2.1.1",
     "dependency-graph": "0.8.0",
@@ -69,33 +69,33 @@
     "express": "4.16.4",
     "express-brute": "1.0.1",
     "express-session": "1.16.1",
-    "file-type": "10.7.1",
-    "filesize": "4.0.0",
+    "file-type": "10.11.0",
+    "filesize": "4.1.2",
     "fs-extra": "7.0.1",
     "getos": "3.1.1",
-    "graphql": "14.1.1",
+    "graphql": "14.2.1",
     "graphql-list-fields": "2.0.2",
-    "graphql-rate-limit-directive": "0.1.0",
-    "graphql-subscriptions": "1.0.0",
+    "graphql-rate-limit-directive": "1.0.1",
+    "graphql-subscriptions": "1.1.0",
     "graphql-tools": "4.0.4",
-    "graphql-upload": "8.0.5",
-    "highlight.js": "9.14.2",
-    "i18next": "14.0.1",
-    "i18next-express-middleware": "1.7.1",
+    "graphql-upload": "8.0.6",
+    "highlight.js": "9.15.6",
+    "i18next": "15.1.0",
+    "i18next-express-middleware": "1.8.0",
     "i18next-localstorage-cache": "1.1.1",
-    "i18next-node-fs-backend": "2.1.1",
-    "image-size": "0.7.1",
+    "i18next-node-fs-backend": "2.1.3",
+    "image-size": "0.7.4",
     "js-base64": "2.5.1",
     "js-binary": "1.2.0",
-    "js-yaml": "3.12.1",
-    "jsonwebtoken": "8.4.0",
+    "js-yaml": "3.13.1",
+    "jsonwebtoken": "8.5.1",
     "klaw": "3.0.0",
-    "knex": "0.16.3",
+    "knex": "0.16.5",
     "lodash": "4.17.11",
     "markdown-it": "8.4.2",
     "markdown-it-abbr": "1.0.4",
     "markdown-it-anchor": "5.0.2",
-    "markdown-it-attrs": "2.3.2",
+    "markdown-it-attrs": "2.3.3",
     "markdown-it-emoji": "1.4.0",
     "markdown-it-expand-tabs": "1.0.13",
     "markdown-it-external-links": "0.0.6",
@@ -107,19 +107,19 @@
     "markdown-it-sup": "1.0.0",
     "markdown-it-task-lists": "2.1.1",
     "mathjax-node": "2.1.1",
-    "mime-types": "2.1.21",
+    "mime-types": "2.1.24",
     "moment": "2.24.0",
-    "moment-timezone": "0.5.23",
-    "mongodb": "3.1.13",
-    "mssql": "5.0.0-beta.1",
+    "moment-timezone": "0.5.25",
+    "mongodb": "3.2.3",
+    "mssql": "5.1.0",
     "multer": "1.4.1",
-    "mysql2": "1.6.4",
+    "mysql2": "1.6.5",
     "nanoid": "2.0.1",
     "node-2fa": "1.1.2",
     "node-cache": "4.2.0",
-    "nodemailer": "5.1.1",
-    "objection": "1.5.3",
-    "ora": "3.0.0",
+    "nodemailer": "6.1.1",
+    "objection": "1.6.8",
+    "ora": "3.4.0",
     "passport": "0.4.0",
     "passport-auth0": "1.1.0",
     "passport-azure-ad-oauth2": "0.0.4",
@@ -128,52 +128,52 @@
     "passport-dropbox-oauth2": "1.1.0",
     "passport-facebook": "3.0.0",
     "passport-github2": "0.1.11",
-    "passport-google-oauth20": "1.0.0",
+    "passport-google-oauth20": "2.0.0",
     "passport-jwt": "4.0.0",
-    "passport-ldapauth": "2.1.1",
+    "passport-ldapauth": "2.1.3",
     "passport-local": "1.0.0",
-    "passport-oauth2": "1.4.0",
+    "passport-microsoft": "0.0.5",
+    "passport-oauth2": "1.5.0",
     "passport-okta-oauth": "0.0.1",
     "passport-openidconnect": "0.0.2",
     "passport-saml": "1.0.0",
     "passport-twitch": "1.0.3",
-    "passport-windowslive": "1.0.2",
     "pem-jwk": "2.0.0",
-    "pg": "7.8.0",
+    "pg": "7.10.0",
     "pg-hstore": "2.3.2",
     "pg-query-stream": "2.0.0",
-    "pg-tsquery": "8.0.3",
-    "pm2": "3.2.9",
+    "pg-tsquery": "8.0.4",
+    "pm2": "3.5.0",
     "pug": "2.0.3",
     "qr-image": "3.2.0",
     "raven": "2.6.4",
     "remove-markdown": "0.3.0",
     "request": "2.88.0",
-    "request-promise": "4.2.2",
-    "safe-regex": "2.0.1",
+    "request-promise": "4.2.4",
+    "safe-regex": "2.0.2",
     "scim-query-filter-parser": "1.1.0",
-    "semver": "5.6.0",
+    "semver": "6.0.0",
     "serve-favicon": "2.5.0",
-    "simple-git": "1.107.0",
+    "simple-git": "1.110.0",
     "solr-node": "1.1.3",
     "sqlite3": "4.0.6",
     "striptags": "3.1.1",
-    "subscriptions-transport-ws": "0.9.15",
+    "subscriptions-transport-ws": "0.9.16",
     "tar-fs": "2.0.0",
-    "twemoji": "11.3.0",
+    "twemoji": "12.0.1",
     "uslug": "1.0.4",
     "uuid": "3.3.2",
     "validate.js": "0.12.0",
     "validator": "10.11.0",
     "validator-as-promised": "1.0.2",
     "winston": "3.2.1",
-    "yargs": "12.0.5"
+    "yargs": "13.2.2"
   },
   "devDependencies": {
-    "@babel/cli": "^7.2.3",
-    "@babel/core": "^7.2.2",
-    "@babel/plugin-proposal-class-properties": "^7.3.0",
-    "@babel/plugin-proposal-decorators": "^7.3.0",
+    "@babel/cli": "^7.4.3",
+    "@babel/core": "^7.4.3",
+    "@babel/plugin-proposal-class-properties": "^7.4.0",
+    "@babel/plugin-proposal-decorators": "^7.4.0",
     "@babel/plugin-proposal-export-namespace-from": "^7.2.0",
     "@babel/plugin-proposal-function-sent": "^7.2.0",
     "@babel/plugin-proposal-json-strings": "^7.2.0",
@@ -181,62 +181,62 @@
     "@babel/plugin-proposal-throw-expressions": "^7.2.0",
     "@babel/plugin-syntax-dynamic-import": "^7.2.0",
     "@babel/plugin-syntax-import-meta": "^7.2.0",
-    "@babel/polyfill": "^7.2.5",
-    "@babel/preset-env": "^7.3.1",
+    "@babel/polyfill": "^7.4.3",
+    "@babel/preset-env": "^7.4.3",
     "@panter/vue-i18next": "0.15.0",
     "animate-sass": "0.8.2",
-    "animated-number-vue": "0.1.4",
-    "apollo-cache-inmemory": "1.4.2",
+    "animated-number-vue": "0.1.5",
+    "apollo-cache-inmemory": "1.5.1",
     "apollo-client": "2.4.12",
-    "apollo-link": "1.2.8",
-    "apollo-link-batch-http": "1.2.8",
-    "apollo-link-error": "1.1.7",
-    "apollo-link-http": "1.5.11",
+    "apollo-link": "1.2.11",
+    "apollo-link-batch-http": "1.2.11",
+    "apollo-link-error": "1.1.10",
+    "apollo-link-http": "1.5.14",
     "apollo-link-persisted-queries": "0.2.2",
-    "apollo-link-ws": "1.0.14",
+    "apollo-link-ws": "1.0.17",
     "apollo-upload-client": "10.0.0",
-    "apollo-utilities": "1.1.2",
-    "autoprefixer": "9.4.7",
+    "apollo-utilities": "1.2.1",
+    "autoprefixer": "9.5.1",
     "babel-eslint": "10.0.1",
-    "babel-jest": "24.0.0",
+    "babel-jest": "24.7.1",
     "babel-loader": "^8.0.5",
-    "babel-plugin-graphql-tag": "1.6.0",
+    "babel-plugin-graphql-tag": "2.1.0",
     "babel-plugin-lodash": "3.3.4",
     "babel-plugin-transform-imports": "1.5.1",
     "brace": "0.11.1",
-    "cache-loader": "2.0.1",
-    "chart.js": "2.7.3",
-    "clean-webpack-plugin": "1.0.1",
-    "copy-webpack-plugin": "4.6.0",
+    "cache-loader": "3.0.0",
+    "chart.js": "2.8.0",
+    "clean-webpack-plugin": "2.0.1",
+    "copy-webpack-plugin": "5.0.3",
     "core-js": "2.6.3",
-    "css-loader": "2.1.0",
-    "cssnano": "4.1.8",
+    "css-loader": "2.1.1",
+    "cssnano": "4.1.10",
     "duplicate-package-checker-webpack-plugin": "3.0.0",
     "epic-spinners": "1.0.4",
-    "eslint": "5.13.0",
+    "eslint": "5.16.0",
     "eslint-config-requarks": "1.0.7",
     "eslint-config-standard": "12.0.0",
-    "eslint-plugin-import": "2.16.0",
+    "eslint-plugin-import": "2.17.2",
     "eslint-plugin-node": "8.0.1",
-    "eslint-plugin-promise": "4.0.1",
+    "eslint-plugin-promise": "4.1.1",
     "eslint-plugin-standard": "4.0.0",
-    "eslint-plugin-vue": "5.1.0",
+    "eslint-plugin-vue": "5.2.2",
     "file-loader": "3.0.1",
-    "filepond": "4.2.0",
-    "filepond-plugin-file-validate-type": "1.2.2",
+    "filepond": "4.4.0",
+    "filepond-plugin-file-validate-type": "1.2.4",
     "filesize.js": "1.0.2",
-    "grapesjs": "0.14.52",
-    "graphiql": "0.12.0",
+    "grapesjs": "0.14.57",
+    "graphiql": "0.13.0",
     "graphql-persisted-document-loader": "1.0.1",
     "graphql-tag": "^2.10.1",
-    "graphql-voyager": "1.0.0-rc.26",
+    "graphql-voyager": "1.0.0-rc.27",
     "hammerjs": "2.0.8",
     "html-webpack-plugin": "3.2.0",
     "html-webpack-pug-plugin": "0.3.0",
-    "i18next-xhr-backend": "1.5.1",
+    "i18next-xhr-backend": "2.0.1",
     "ignore-loader": "0.1.2",
     "js-cookie": "2.2.0",
-    "mini-css-extract-plugin": "0.5.0",
+    "mini-css-extract-plugin": "0.6.0",
     "moment-duration-format": "2.2.2",
     "node-sass": "4.11.0",
     "offline-plugin": "5.0.6",
@@ -246,15 +246,15 @@
     "postcss-flexibility": "2.0.0",
     "postcss-import": "12.0.1",
     "postcss-loader": "3.0.0",
-    "postcss-preset-env": "6.5.0",
-    "postcss-selector-parser": "5.0.0",
+    "postcss-preset-env": "6.6.0",
+    "postcss-selector-parser": "6.0.2",
     "pug-lint": "2.5.0",
     "pug-loader": "2.4.0",
     "pug-plain-loader": "1.0.0",
-    "raw-loader": "1.0.0",
-    "react": "16.7.0",
-    "react-dom": "16.7.0",
-    "resolve-url-loader": "3.0.0",
+    "raw-loader": "2.0.0",
+    "react": "16.8.6",
+    "react-dom": "16.8.6",
+    "resolve-url-loader": "3.1.0",
     "sass-loader": "7.1.0",
     "sass-resources-loader": "2.0.0",
     "script-ext-html-webpack-plugin": "2.1.3",
@@ -264,41 +264,41 @@
     "stylus-loader": "3.0.2",
     "twemoji-awesome": "1.0.6",
     "url-loader": "1.1.2",
-    "vee-validate": "2.1.7",
+    "vee-validate": "2.2.5",
     "velocity-animate": "1.5.2",
     "viz.js": "2.1.2",
-    "vue": "2.5.22",
-    "vue-apollo": "3.0.0-beta.27",
-    "vue-chartjs": "3.4.0",
+    "vue": "2.6.10",
+    "vue-apollo": "3.0.0-beta.28",
+    "vue-chartjs": "3.4.2",
     "vue-clipboards": "1.2.4",
     "vue-codemirror": "4.0.6",
-    "vue-filepond": "5.0.0",
-    "vue-hot-reload-api": "2.3.1",
-    "vue-loader": "15.6.2",
-    "vue-material-design-icons": "3.0.0",
+    "vue-filepond": "5.1.0",
+    "vue-hot-reload-api": "2.3.3",
+    "vue-loader": "15.7.0",
+    "vue-material-design-icons": "3.2.0",
     "vue-moment": "4.0.0",
-    "vue-router": "3.0.2",
+    "vue-router": "3.0.6",
     "vue-simple-breakpoints": "1.0.3",
     "vue-status-indicator": "1.1.1",
-    "vue-template-compiler": "2.5.22",
+    "vue-template-compiler": "2.6.10",
     "vue-tour": "1.1.0",
     "vue2-animate": "2.1.0",
-    "vuedraggable": "2.17.0",
-    "vuescroll": "4.10.2",
-    "vuetify": "1.4.4",
+    "vuedraggable": "2.20.0",
+    "vuescroll": "4.12.2",
+    "vuetify": "1.5.13",
     "vuex": "3.1.0",
-    "vuex-pathify": "1.1.3",
+    "vuex-pathify": "1.2.2",
     "vuex-persistedstate": "2.5.4",
-    "webpack": "4.29.0",
-    "webpack-bundle-analyzer": "3.0.3",
-    "webpack-cli": "3.2.1",
-    "webpack-dev-middleware": "3.5.1",
-    "webpack-hot-middleware": "2.24.3",
+    "webpack": "4.30.0",
+    "webpack-bundle-analyzer": "3.3.2",
+    "webpack-cli": "3.3.1",
+    "webpack-dev-middleware": "3.6.2",
+    "webpack-hot-middleware": "2.24.4",
     "webpack-merge": "4.2.1",
     "webpack-subresource-integrity": "1.3.2",
     "whatwg-fetch": "3.0.0",
     "write-file-webpack-plugin": "4.5.0",
-    "xterm": "3.11.0",
+    "xterm": "3.12.2",
     "zxcvbn": "4.4.2"
   },
   "resolutions": {

+ 0 - 1
server/controllers/auth.js

@@ -17,7 +17,6 @@ router.get('/login/:strategy', async (req, res, next) => {
     const authResult = await WIKI.models.users.login({
       strategy: req.params.strategy
     }, { req, res })
-    console.info(authResult)
   } catch (err) {
     next(err)
   }

+ 7 - 2
server/helpers/page.js

@@ -5,6 +5,8 @@ const crypto = require('crypto')
 const localeSegmentRegex = /^[A-Z]{2}(-[A-Z]{2})?$/gi
 const systemSegmentRegex = /^[A-Z]\//gi
 
+/* global WIKI */
+
 module.exports = {
   /**
    * Parse raw url path and make it safe
@@ -63,7 +65,10 @@ module.exports = {
   /**
    * Check if path is a reserved path
    */
-  isReservedPath(rawPath)  {
-    return _.some(WIKI.data.reservedPaths, p => _.startsWith(rawPath, p)) || systemSegmentRegex.test(rawPath)
+  isReservedPath(rawPath) {
+    const firstSection = _.head(rawPath.split('/'))
+    return _.some(WIKI.data.reservedPaths, p => {
+      return p === firstSection || systemSegmentRegex.test(rawPath)
+    })
   }
 }

+ 23 - 10
server/modules/authentication/ldap/authentication.js

@@ -6,10 +6,11 @@
 
 const LdapStrategy = require('passport-ldapauth').Strategy
 const fs = require('fs')
+const _ = require('lodash')
 
 module.exports = {
   init (passport, conf) {
-    passport.use('ldapauth',
+    passport.use('ldap',
       new LdapStrategy({
         server: {
           url: conf.url,
@@ -17,7 +18,6 @@ module.exports = {
           bindCredentials: conf.bindCredentials,
           searchBase: conf.searchBase,
           searchFilter: conf.searchFilter,
-          searchAttributes: ['displayName', 'name', 'cn', 'mail'],
           tlsOptions: (conf.tlsEnabled) ? {
             ca: [
               fs.readFileSync(conf.tlsCertPath)
@@ -25,15 +25,28 @@ module.exports = {
           } : {}
         },
         usernameField: 'email',
+        passwordField: 'password',
         passReqToCallback: false
-      }, (profile, cb) => {
-        profile.provider = 'ldap'
-        profile.id = profile.dn
-        WIKI.models.users.processProfile(profile).then((user) => {
-          return cb(null, user) || true
-        }).catch((err) => {
-          return cb(err, null) || true
-        })
+      }, async (profile, cb) => {
+        try {
+          const userId = _.get(profile, conf.mappingUID, null)
+          if (!userId) {
+            throw new Error('Invalid Unique ID field mapping!')
+          }
+
+          const user = await WIKI.models.users.processProfile({
+            profile: {
+              id: userId,
+              email: _.get(profile, conf.mappingEmail, ''),
+              displayName: _.get(profile, conf.mappingDisplayName, '???'),
+              picture: _.get(profile, conf.mappingPicture, '')
+            },
+            providerKey: 'ldap'
+          })
+          cb(null, user)
+        } catch (err) {
+          cb(err, null)
+        }
       }
       ))
   }

+ 41 - 5
server/modules/authentication/ldap/definition.yml

@@ -5,33 +5,69 @@ author: requarks.io
 logo: https://static.requarks.io/logo/active-directory.svg
 color: blue darken-3
 website: https://www.microsoft.com/windowsserver
+isAvailable: true
 useForm: true
 props:
   url:
-    title: URL
+    title: LDAP URL
     type: String
     default: 'ldap://serverhost:389'
-    hint: (e.g. ldap://serverhost:389)
+    hint: (e.g. ldap://serverhost:389 or ldaps://serverhost:636)
+    order: 1
   bindDn:
-    title: Bind DN
+    title: Admin Bind DN
     type: String
     default: cn='root'
     hint: The dstinguished name (dn) of the account used for binding.
+    order: 2
   bindCredentials:
+    title: Admin Bind Credentials
     type: String
-    hint: The password of the account used for binding.
+    hint: The password of the account used above for binding.
+    order: 3
   searchBase:
+    title: Search Base
     type: String
     default: 'o=users,o=example.com'
+    hint: The base DN from which to search for users.
+    order: 4
   searchFilter:
+    title: Search Filter
     type: String
     default: '(uid={{username}})'
-    hint: The query to use to match username. {{username}} must be present.
+    hint: The query to use to match username. {{username}} must be present and will be interpolated with the user provided username when performing the LDAP search.
+    order: 5
   tlsEnabled:
     title: Use TLS
     type: Boolean
     default: false
+    order: 6
   tlsCertPath:
     title: TLS Certificate Path
     type: String
     hint: Absolute path to the TLS certificate on the server.
+    order: 7
+  mappingUID:
+    title: Unique ID Field Mapping
+    type: String
+    default: 'uid'
+    hint: The field storing the user unique identifier. Usually "uid" or "sAMAccountName".
+    order: 8
+  mappingEmail:
+    title: Email Field Mapping
+    type: String
+    default: 'mail'
+    hint: The field storing the user email. Usually "mail".
+    order: 9
+  mappingDisplayName:
+    title: Display Name Field Mapping
+    type: String
+    default: 'displayName'
+    hint: The field storing the user display name. Usually "displayName" or "cn".
+    order: 10
+  mappingPicture:
+    title: Avatar Picture Field Mapping
+    type: String
+    default: 'jpegPhoto'
+    hint: The field storing the user avatar picture. Usually "jpegPhoto" or "thumbnailPhoto".
+    order: 11

+ 4 - 2
server/modules/authentication/microsoft/authentication.js

@@ -4,7 +4,8 @@
 // Microsoft Account
 // ------------------------------------
 
-const WindowsLiveStrategy = require('passport-windowslive').Strategy
+const WindowsLiveStrategy = require('passport-microsoft').Strategy
+const _ = require('lodash')
 
 module.exports = {
   init (passport, conf) {
@@ -12,7 +13,8 @@ module.exports = {
       new WindowsLiveStrategy({
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
-        callbackURL: conf.callbackURL
+        callbackURL: conf.callbackURL,
+        scope: ['User.Read', 'email', 'openid', 'profile']
       }, async (accessToken, refreshToken, profile, cb) => {
         console.info(profile)
         try {

文件差异内容过多而无法显示
+ 459 - 204
yarn.lock


部分文件因为文件数量过多而无法显示