瀏覽代碼

[web] upgrade @node-oauth/oauth2-server to ^5.1.0, (#16705)

* [web] upgrade @node-oauth/oauth2-server to ^5.1.0,

* Added `expressify` to middleware returned by Authentication.requireOauth()

* Extracted OAuth2 scope transformation to utilities

* Throw an error with undefined SAML scopes

GitOrigin-RevId: 00dfe81c707e9a3fcf9bb10e007c1fc646f7b9dd
Miguel Serrano 2 年之前
父節點
當前提交
abe33de010

+ 11 - 106
package-lock.json

@@ -7025,18 +7025,16 @@
       "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA=="
     },
     "node_modules/@node-oauth/oauth2-server": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-4.3.0.tgz",
-      "integrity": "sha512-QxSWMPwiEFwZczFbZRJjmzsRT9rgb3FhBw/rZlFe9+ZrOWEc6r7mFCcvX14ekxLHSxAxZEYIgzUtE4yHfKiTxg==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-5.1.0.tgz",
+      "integrity": "sha512-sYvqL1GeZLRSwgl++/oOzxJj/ZBe2yXnp6E5LGNQ5qjpn0+t/dwquXILUe3Sk2Y8/wU7XeRxToOtBVeSVkuJag==",
       "dependencies": {
-        "@node-oauth/formats": "^1.0.0",
+        "@node-oauth/formats": "1.0.0",
         "basic-auth": "2.0.1",
-        "bluebird": "3.7.2",
-        "promisify-any": "2.0.1",
         "type-is": "1.6.18"
       },
       "engines": {
-        "node": ">=14.0.0"
+        "node": ">=16.0.0"
       }
     },
     "node_modules/@node-rs/crc32": {
@@ -19756,31 +19754,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/co-bluebird": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz",
-      "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=",
-      "dependencies": {
-        "bluebird": "^2.10.0",
-        "co-use": "^1.1.0"
-      },
-      "engines": {
-        "node": ">=0.12.0"
-      }
-    },
-    "node_modules/co-bluebird/node_modules/bluebird": {
-      "version": "2.11.0",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
-      "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
-    },
-    "node_modules/co-use": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz",
-      "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=",
-      "engines": {
-        "node": ">=0.12.0"
-      }
-    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -28085,11 +28058,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/is-generator": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz",
-      "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM="
-    },
     "node_modules/is-generator-function": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
@@ -35458,24 +35426,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/promisify-any": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz",
-      "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=",
-      "dependencies": {
-        "bluebird": "^2.10.0",
-        "co-bluebird": "^1.1.0",
-        "is-generator": "^1.0.2"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/promisify-any/node_modules/bluebird": {
-      "version": "2.11.0",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
-      "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
-    },
     "node_modules/promptly": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/promptly/-/promptly-3.2.0.tgz",
@@ -46077,7 +46027,7 @@
         "@contentful/rich-text-html-renderer": "^16.0.2",
         "@contentful/rich-text-types": "^16.0.2",
         "@google-cloud/bigquery": "^6.0.1",
-        "@node-oauth/oauth2-server": "^4.3.0",
+        "@node-oauth/oauth2-server": "^5.1.0",
         "@node-saml/passport-saml": "^4.0.4",
         "@overleaf/access-token-encryptor": "*",
         "@overleaf/fetch-utils": "*",
@@ -52367,14 +52317,12 @@
       "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA=="
     },
     "@node-oauth/oauth2-server": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-4.3.0.tgz",
-      "integrity": "sha512-QxSWMPwiEFwZczFbZRJjmzsRT9rgb3FhBw/rZlFe9+ZrOWEc6r7mFCcvX14ekxLHSxAxZEYIgzUtE4yHfKiTxg==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-5.1.0.tgz",
+      "integrity": "sha512-sYvqL1GeZLRSwgl++/oOzxJj/ZBe2yXnp6E5LGNQ5qjpn0+t/dwquXILUe3Sk2Y8/wU7XeRxToOtBVeSVkuJag==",
       "requires": {
-        "@node-oauth/formats": "^1.0.0",
+        "@node-oauth/formats": "1.0.0",
         "basic-auth": "2.0.1",
-        "bluebird": "3.7.2",
-        "promisify-any": "2.0.1",
         "type-is": "1.6.18"
       }
     },
@@ -55025,7 +54973,7 @@
         "@lezer/highlight": "^1.1.6",
         "@lezer/lr": "^1.3.13",
         "@lezer/markdown": "^1.1.0",
-        "@node-oauth/oauth2-server": "^4.3.0",
+        "@node-oauth/oauth2-server": "^5.1.0",
         "@node-saml/passport-saml": "^4.0.4",
         "@opentelemetry/api": "^1.4.1",
         "@opentelemetry/auto-instrumentations-web": "^0.33.1",
@@ -64665,27 +64613,6 @@
       "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
       "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw=="
     },
-    "co-bluebird": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz",
-      "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=",
-      "requires": {
-        "bluebird": "^2.10.0",
-        "co-use": "^1.1.0"
-      },
-      "dependencies": {
-        "bluebird": {
-          "version": "2.11.0",
-          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
-          "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
-        }
-      }
-    },
-    "co-use": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz",
-      "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI="
-    },
     "color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -71007,11 +70934,6 @@
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
     },
-    "is-generator": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz",
-      "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM="
-    },
     "is-generator-function": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
@@ -77508,23 +77430,6 @@
         "es-abstract": "^1.19.1"
       }
     },
-    "promisify-any": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz",
-      "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=",
-      "requires": {
-        "bluebird": "^2.10.0",
-        "co-bluebird": "^1.1.0",
-        "is-generator": "^1.0.2"
-      },
-      "dependencies": {
-        "bluebird": {
-          "version": "2.11.0",
-          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
-          "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
-        }
-      }
-    },
     "promptly": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/promptly/-/promptly-3.2.0.tgz",

+ 24 - 25
services/web/app/src/Features/Authentication/AuthenticationController.js

@@ -26,6 +26,7 @@ const {
 const { ParallelLoginError } = require('./AuthenticationErrors')
 const { hasAdminAccess } = require('../Helpers/AdminAuthorizationHelper')
 const Modules = require('../../infrastructure/Modules')
+const { expressify } = require('@overleaf/promise-utils')
 
 function send401WithChallenge(res) {
   res.setHeader('WWW-Authenticate', 'OverleafLogin')
@@ -320,35 +321,33 @@ const AuthenticationController = {
 
     // require this here because module may not be included in some versions
     const Oauth2Server = require('../../../../modules/oauth2-server/app/src/Oauth2Server')
-    return function (req, res, next) {
+    const middleware = async (req, res, next) => {
       const request = new Oauth2Server.Request(req)
       const response = new Oauth2Server.Response(res)
-      Oauth2Server.server.authenticate(
-        request,
-        response,
-        { scope },
-        function (err, token) {
-          if (err) {
-            // use a 401 status code for malformed header for git-bridge
-            if (
-              err.code === 400 &&
-              err.message === 'Invalid request: malformed authorization header'
-            ) {
-              err.code = 401
-            }
-            // send all other errors
-            res
-              .status(err.code)
-              .json({ error: err.name, error_description: err.message })
-          } else {
-            req.oauth = { access_token: token.accessToken }
-            req.oauth_token = token
-            req.oauth_user = token.user
-            next()
-          }
+      try {
+        const token = await Oauth2Server.server.authenticate(
+          request,
+          response,
+          { scope }
+        )
+        req.oauth = { access_token: token.accessToken }
+        req.oauth_token = token
+        req.oauth_user = token.user
+        next()
+      } catch (err) {
+        if (
+          err.code === 400 &&
+          err.message === 'Invalid request: malformed authorization header'
+        ) {
+          err.code = 401
         }
-      )
+        // send all other errors
+        res
+          .status(err.code)
+          .json({ error: err.name, error_description: err.message })
+      }
     }
+    return expressify(middleware)
   },
 
   validateUserSession: function () {

+ 1 - 1
services/web/package.json

@@ -69,7 +69,7 @@
     "@contentful/rich-text-html-renderer": "^16.0.2",
     "@contentful/rich-text-types": "^16.0.2",
     "@google-cloud/bigquery": "^6.0.1",
-    "@node-oauth/oauth2-server": "^4.3.0",
+    "@node-oauth/oauth2-server": "^5.1.0",
     "@node-saml/passport-saml": "^4.0.4",
     "@overleaf/access-token-encryptor": "*",
     "@overleaf/fetch-utils": "*",

+ 8 - 9
services/web/test/unit/src/Authentication/AuthenticationControllerTests.js

@@ -578,13 +578,15 @@ describe('AuthenticationController', function () {
     })
 
     describe('when Oauth2Server authenticates', function () {
-      beforeEach(function () {
+      beforeEach(function (done) {
         this.token = {
           accessToken: 'token',
           user: 'user',
         }
-        this.Oauth2Server.server.authenticate.yields(null, this.token)
-        this.middleware(this.req, this.res, this.next)
+        this.Oauth2Server.server.authenticate = sinon
+          .stub()
+          .resolves(this.token)
+        this.middleware(this.req, this.res, () => done())
       })
 
       it('should set oauth_token on request', function () {
@@ -598,15 +600,12 @@ describe('AuthenticationController', function () {
       it('should set oauth_user on request', function () {
         this.req.oauth_user.should.equal('user')
       })
-
-      it('should call next', function () {
-        this.next.should.have.been.calledOnce
-      })
     })
 
     describe('when Oauth2Server returns 401 error', function () {
-      beforeEach(function () {
-        this.Oauth2Server.server.authenticate.yields({ code: 401 })
+      beforeEach(function (done) {
+        this.res.json.callsFake(() => done())
+        this.Oauth2Server.server.authenticate.rejects({ code: 401 })
         this.middleware(this.req, this.res, this.next)
       })