[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
This commit is contained in:
Miguel Serrano 2024-02-07 11:01:00 +01:00 committed by Copybot
parent 4e689233a5
commit abe33de010
4 changed files with 44 additions and 141 deletions

117
package-lock.json generated
View file

@ -7025,18 +7025,16 @@
"integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA==" "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA=="
}, },
"node_modules/@node-oauth/oauth2-server": { "node_modules/@node-oauth/oauth2-server": {
"version": "4.3.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-4.3.0.tgz", "resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-5.1.0.tgz",
"integrity": "sha512-QxSWMPwiEFwZczFbZRJjmzsRT9rgb3FhBw/rZlFe9+ZrOWEc6r7mFCcvX14ekxLHSxAxZEYIgzUtE4yHfKiTxg==", "integrity": "sha512-sYvqL1GeZLRSwgl++/oOzxJj/ZBe2yXnp6E5LGNQ5qjpn0+t/dwquXILUe3Sk2Y8/wU7XeRxToOtBVeSVkuJag==",
"dependencies": { "dependencies": {
"@node-oauth/formats": "^1.0.0", "@node-oauth/formats": "1.0.0",
"basic-auth": "2.0.1", "basic-auth": "2.0.1",
"bluebird": "3.7.2",
"promisify-any": "2.0.1",
"type-is": "1.6.18" "type-is": "1.6.18"
}, },
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=16.0.0"
} }
}, },
"node_modules/@node-rs/crc32": { "node_modules/@node-rs/crc32": {
@ -19756,31 +19754,6 @@
"node": ">=0.10.0" "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": { "node_modules/color-convert": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -28085,11 +28058,6 @@
"node": ">=8" "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": { "node_modules/is-generator-function": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "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" "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": { "node_modules/promptly": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/promptly/-/promptly-3.2.0.tgz", "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-html-renderer": "^16.0.2",
"@contentful/rich-text-types": "^16.0.2", "@contentful/rich-text-types": "^16.0.2",
"@google-cloud/bigquery": "^6.0.1", "@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", "@node-saml/passport-saml": "^4.0.4",
"@overleaf/access-token-encryptor": "*", "@overleaf/access-token-encryptor": "*",
"@overleaf/fetch-utils": "*", "@overleaf/fetch-utils": "*",
@ -52367,14 +52317,12 @@
"integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA==" "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA=="
}, },
"@node-oauth/oauth2-server": { "@node-oauth/oauth2-server": {
"version": "4.3.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-4.3.0.tgz", "resolved": "https://registry.npmjs.org/@node-oauth/oauth2-server/-/oauth2-server-5.1.0.tgz",
"integrity": "sha512-QxSWMPwiEFwZczFbZRJjmzsRT9rgb3FhBw/rZlFe9+ZrOWEc6r7mFCcvX14ekxLHSxAxZEYIgzUtE4yHfKiTxg==", "integrity": "sha512-sYvqL1GeZLRSwgl++/oOzxJj/ZBe2yXnp6E5LGNQ5qjpn0+t/dwquXILUe3Sk2Y8/wU7XeRxToOtBVeSVkuJag==",
"requires": { "requires": {
"@node-oauth/formats": "^1.0.0", "@node-oauth/formats": "1.0.0",
"basic-auth": "2.0.1", "basic-auth": "2.0.1",
"bluebird": "3.7.2",
"promisify-any": "2.0.1",
"type-is": "1.6.18" "type-is": "1.6.18"
} }
}, },
@ -55025,7 +54973,7 @@
"@lezer/highlight": "^1.1.6", "@lezer/highlight": "^1.1.6",
"@lezer/lr": "^1.3.13", "@lezer/lr": "^1.3.13",
"@lezer/markdown": "^1.1.0", "@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", "@node-saml/passport-saml": "^4.0.4",
"@opentelemetry/api": "^1.4.1", "@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-web": "^0.33.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", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
"integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" "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": { "color-convert": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "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", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" "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": { "is-generator-function": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
@ -77508,23 +77430,6 @@
"es-abstract": "^1.19.1" "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": { "promptly": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/promptly/-/promptly-3.2.0.tgz", "resolved": "https://registry.npmjs.org/promptly/-/promptly-3.2.0.tgz",

View file

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

View file

@ -69,7 +69,7 @@
"@contentful/rich-text-html-renderer": "^16.0.2", "@contentful/rich-text-html-renderer": "^16.0.2",
"@contentful/rich-text-types": "^16.0.2", "@contentful/rich-text-types": "^16.0.2",
"@google-cloud/bigquery": "^6.0.1", "@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", "@node-saml/passport-saml": "^4.0.4",
"@overleaf/access-token-encryptor": "*", "@overleaf/access-token-encryptor": "*",
"@overleaf/fetch-utils": "*", "@overleaf/fetch-utils": "*",

View file

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