mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
[web] Clear hardcoded password in external SP auth (#33597)
registerExternalAuthAdmin() now generates a random password on admin registration. A migration clears the password for existing installs only in CE/SP GitOrigin-RevId: 94a82d35dc8cd46915c31fb24f477c19367025eb
This commit is contained in:
@@ -2,6 +2,7 @@ import OError from '@overleaf/o-error'
|
|||||||
import { expressify } from '@overleaf/promise-utils'
|
import { expressify } from '@overleaf/promise-utils'
|
||||||
import Settings from '@overleaf/settings'
|
import Settings from '@overleaf/settings'
|
||||||
import Path from 'node:path'
|
import Path from 'node:path'
|
||||||
|
import crypto from 'node:crypto'
|
||||||
import logger from '@overleaf/logger'
|
import logger from '@overleaf/logger'
|
||||||
import UserRegistrationHandler from '../../../../app/src/Features/User/UserRegistrationHandler.mjs'
|
import UserRegistrationHandler from '../../../../app/src/Features/User/UserRegistrationHandler.mjs'
|
||||||
import EmailHandler from '../../../../app/src/Features/Email/EmailHandler.mjs'
|
import EmailHandler from '../../../../app/src/Features/Email/EmailHandler.mjs'
|
||||||
@@ -124,12 +125,12 @@ function registerExternalAuthAdmin(authMethod) {
|
|||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
email,
|
email,
|
||||||
password: 'password_here',
|
password: crypto.randomBytes(32).toString('hex'),
|
||||||
first_name: email,
|
first_name: email,
|
||||||
last_name: '',
|
last_name: '',
|
||||||
}
|
}
|
||||||
logger.debug(
|
logger.debug(
|
||||||
{ body, authMethod },
|
{ email, authMethod },
|
||||||
'creating admin account for specified external-auth user'
|
'creating admin account for specified external-auth user'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -759,14 +759,16 @@ describe('LaunchpadController', function () {
|
|||||||
ctx.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
|
ctx.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
ctx.UserRegistrationHandler.promises.registerNewUser
|
const call =
|
||||||
.calledWith({
|
ctx.UserRegistrationHandler.promises.registerNewUser.firstCall
|
||||||
email: ctx.email,
|
expect(call.args[0]).to.include({
|
||||||
password: 'password_here',
|
email: ctx.email,
|
||||||
first_name: ctx.email,
|
first_name: ctx.email,
|
||||||
last_name: '',
|
last_name: '',
|
||||||
})
|
})
|
||||||
.should.equal(true)
|
expect(call.args[0].password).to.be.a('string')
|
||||||
|
expect(call.args[0].password).to.not.equal('password_here')
|
||||||
|
expect(call.args[0].password.length).to.be.at.least(16)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should have updated the user to make them an admin', function (ctx) {
|
it('should have updated the user to make them an admin', function (ctx) {
|
||||||
@@ -964,14 +966,16 @@ describe('LaunchpadController', function () {
|
|||||||
ctx.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
|
ctx.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
ctx.UserRegistrationHandler.promises.registerNewUser
|
const call =
|
||||||
.calledWith({
|
ctx.UserRegistrationHandler.promises.registerNewUser.firstCall
|
||||||
email: ctx.email,
|
expect(call.args[0]).to.include({
|
||||||
password: 'password_here',
|
email: ctx.email,
|
||||||
first_name: ctx.email,
|
first_name: ctx.email,
|
||||||
last_name: '',
|
last_name: '',
|
||||||
})
|
})
|
||||||
.should.equal(true)
|
expect(call.args[0].password).to.be.a('string')
|
||||||
|
expect(call.args[0].password).to.not.equal('password_here')
|
||||||
|
expect(call.args[0].password.length).to.be.at.least(16)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not call update', function (ctx) {
|
it('should not call update', function (ctx) {
|
||||||
@@ -1015,14 +1019,16 @@ describe('LaunchpadController', function () {
|
|||||||
ctx.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
|
ctx.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
ctx.UserRegistrationHandler.promises.registerNewUser
|
const call =
|
||||||
.calledWith({
|
ctx.UserRegistrationHandler.promises.registerNewUser.firstCall
|
||||||
email: ctx.email,
|
expect(call.args[0]).to.include({
|
||||||
password: 'password_here',
|
email: ctx.email,
|
||||||
first_name: ctx.email,
|
first_name: ctx.email,
|
||||||
last_name: '',
|
last_name: '',
|
||||||
})
|
})
|
||||||
.should.equal(true)
|
expect(call.args[0].password).to.be.a('string')
|
||||||
|
expect(call.args[0].password).to.not.equal('password_here')
|
||||||
|
expect(call.args[0].password.length).to.be.at.least(16)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import bcrypt from 'bcrypt'
|
||||||
|
import { db } from './lib/mongodb.mjs'
|
||||||
|
import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
|
||||||
|
import { promiseMapWithLimit } from '@overleaf/promise-utils'
|
||||||
|
|
||||||
|
const tags = ['server-ce', 'server-pro']
|
||||||
|
|
||||||
|
const HARDCODED_PASSWORD = 'password_here'
|
||||||
|
const CONCURRENCY = parseInt(process.env.CONCURRENCY, 10) || 10
|
||||||
|
|
||||||
|
const migrate = async () => {
|
||||||
|
await batchedUpdate(
|
||||||
|
db.users,
|
||||||
|
{ hashedPassword: { $type: 'string' } },
|
||||||
|
async function (batch) {
|
||||||
|
await promiseMapWithLimit(CONCURRENCY, batch, async user => {
|
||||||
|
const match = await bcrypt.compare(
|
||||||
|
HARDCODED_PASSWORD,
|
||||||
|
user.hashedPassword
|
||||||
|
)
|
||||||
|
if (match) {
|
||||||
|
await db.users.updateOne(
|
||||||
|
{ _id: user._id, hashedPassword: user.hashedPassword },
|
||||||
|
{ $unset: { hashedPassword: 1 } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ hashedPassword: 1 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rollback = async () => {}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
tags,
|
||||||
|
migrate,
|
||||||
|
rollback,
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
"@overleaf/o-error": "workspace:*",
|
"@overleaf/o-error": "workspace:*",
|
||||||
"@overleaf/promise-utils": "workspace:*",
|
"@overleaf/promise-utils": "workspace:*",
|
||||||
"@overleaf/settings": "workspace:*",
|
"@overleaf/settings": "workspace:*",
|
||||||
|
"bcrypt": "^6.0.0",
|
||||||
"east": "2.0.3",
|
"east": "2.0.3",
|
||||||
"mongodb": "6.12.0"
|
"mongodb": "6.12.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6770,6 +6770,7 @@ __metadata:
|
|||||||
"@overleaf/o-error": "workspace:*"
|
"@overleaf/o-error": "workspace:*"
|
||||||
"@overleaf/promise-utils": "workspace:*"
|
"@overleaf/promise-utils": "workspace:*"
|
||||||
"@overleaf/settings": "workspace:*"
|
"@overleaf/settings": "workspace:*"
|
||||||
|
bcrypt: "npm:^6.0.0"
|
||||||
east: "npm:2.0.3"
|
east: "npm:2.0.3"
|
||||||
mongodb: "npm:6.12.0"
|
mongodb: "npm:6.12.0"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
|
|||||||
Reference in New Issue
Block a user