浏览代码

fix: revocation token list for users + groups

NGPixel 5 年之前
父节点
当前提交
a690e5597f
共有 3 个文件被更改,包括 55 次插入2 次删除
  1. 32 2
      server/core/auth.js
  2. 16 0
      server/graph/resolvers/group.js
  3. 7 0
      server/graph/resolvers/user.js

+ 32 - 2
server/core/auth.js

@@ -19,6 +19,7 @@ module.exports = {
   },
   groups: {},
   validApiKeys: [],
+  revokationList: require('./cache').init(),
 
   /**
    * Initialize the authentication module
@@ -111,10 +112,28 @@ module.exports = {
   authenticate(req, res, next) {
     WIKI.auth.passport.authenticate('jwt', {session: false}, async (err, user, info) => {
       if (err) { return next() }
+      let mustRevalidate = false
 
       // Expired but still valid within N days, just renew
-      if (info instanceof Error && info.name === 'TokenExpiredError' &&
-        moment().subtract(ms(WIKI.config.auth.tokenRenewal), 'ms').isBefore(info.expiredAt)) {
+      if (info instanceof Error && info.name === 'TokenExpiredError' && moment().subtract(ms(WIKI.config.auth.tokenRenewal), 'ms').isBefore(info.expiredAt)) {
+        mustRevalidate = true
+      }
+
+      // Check if user / group is in revokation list
+      if (user) {
+        if (WIKI.auth.revokationList.has(`u${_.toString(user.id)}`)) {
+          mustRevalidate = true
+        }
+        for (const gid of user.groups) {
+          if (WIKI.auth.revokationList.has(`g${_.toString(gid)}`)) {
+            mustRevalidate = true
+          }
+        }
+      }
+
+      // Revalidate and renew token
+      if (mustRevalidate) {
+        console.info('MUST REVALIDATE')
         const jwtPayload = jwt.decode(securityHelper.extractJWT(req))
         try {
           const newToken = await WIKI.models.users.refreshToken(jwtPayload.id)
@@ -380,6 +399,9 @@ module.exports = {
     WIKI.events.inbound.on('reloadAuthStrategies', () => {
       WIKI.auth.activateStrategies()
     })
+    WIKI.events.inbound.on('addAuthRevoke', (args) => {
+      WIKI.auth.revokeUserTokens(args)
+    })
   },
 
   /**
@@ -410,5 +432,13 @@ module.exports = {
         manage: WIKI.auth.checkAccess(req.user, ['manage:system'], page)
       }
     }
+  },
+
+  /**
+   * Add user / group ID to JWT revokation list, forcing all requests to be validated against the latest permissions
+   */
+  revokeUserTokens ({ id, kind = 'u' }) {
+    console.info(Math.ceil(ms(WIKI.config.auth.tokenRenewal) / 1000))
+    WIKI.auth.revokationList.set(`${kind}${_.toString(id)}`, true, Math.ceil(ms(WIKI.config.auth.tokenRenewal) / 1000))
   }
 }

+ 16 - 0
server/graph/resolvers/group.js

@@ -42,6 +42,10 @@ module.exports = {
         throw new gql.GraphQLError('User is already assigned to group.')
       }
       await grp.$relatedQuery('users').relate(usr.id)
+
+      WIKI.auth.revokeUserTokens({ id: usr.id, kind: 'u' })
+      WIKI.events.outbound.emit('addAuthRevoke', { id: usr.id, kind: 'u' })
+
       return {
         responseResult: graphHelper.generateSuccess('User has been assigned to group.')
       }
@@ -62,8 +66,13 @@ module.exports = {
     },
     async delete(obj, args) {
       await WIKI.models.groups.query().deleteById(args.id)
+
+      WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' })
+      WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' })
+
       await WIKI.auth.reloadGroups()
       WIKI.events.outbound.emit('reloadGroups')
+
       return {
         responseResult: graphHelper.generateSuccess('Group has been deleted.')
       }
@@ -78,6 +87,10 @@ module.exports = {
         throw new gql.GraphQLError('Invalid User ID')
       }
       await grp.$relatedQuery('users').unrelate().where('userId', usr.id)
+
+      WIKI.auth.revokeUserTokens({ id: usr.id, kind: 'u' })
+      WIKI.events.outbound.emit('addAuthRevoke', { id: usr.id, kind: 'u' })
+
       return {
         responseResult: graphHelper.generateSuccess('User has been unassigned from group.')
       }
@@ -95,6 +108,9 @@ module.exports = {
         pageRules: JSON.stringify(args.pageRules)
       }).where('id', args.id)
 
+      WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' })
+      WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' })
+
       await WIKI.auth.reloadGroups()
       WIKI.events.outbound.emit('reloadGroups')
 

+ 7 - 0
server/graph/resolvers/user.js

@@ -73,6 +73,10 @@ module.exports = {
           throw new WIKI.Error.UserDeleteProtected()
         }
         await WIKI.models.users.deleteUser(args.id, args.replaceId)
+
+        WIKI.auth.revokeUserTokens({ id: args.id, kind: 'u' })
+        WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'u' })
+
         return {
           responseResult: graphHelper.generateSuccess('User deleted successfully')
         }
@@ -124,6 +128,9 @@ module.exports = {
         }
         await WIKI.models.users.query().patch({ isActive: false }).findById(args.id)
 
+        WIKI.auth.revokeUserTokens({ id: args.id, kind: 'u' })
+        WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'u' })
+
         return {
           responseResult: graphHelper.generateSuccess('User deactivated successfully')
         }