This commit is contained in:
yzx9 2023-11-23 17:06:44 +08:00
parent 242183d601
commit f53790c452
5 changed files with 110 additions and 63 deletions

View File

@ -42,13 +42,10 @@ COPY sharelatex/navbar.pug /overleaf/services/web/app/views/layout/
# Non LDAP User Registration for Admins
COPY sharelatex/admin-index.pug /overleaf/services/web/app/views/admin/index.pug
COPY sharelatex/admin-sysadmin.pug /tmp/admin-sysadmin.pug
## instead of copying the login.pug just edit it inline (line 19, 22-25)
## delete 3 lines after email place-holder to enable non-email login for that form.
RUN sed -iE '/type=.*email.*/d' /overleaf/services/web/app/views/user/login.pug && \
## comment out this line to prevent sed accidently remove the brackets of the email(username) field
# sed -iE '/email@example.com/{n;N;N;d}' /overleaf/services/web/app/views/user/login.pug && \
sed -iE "s/email@example.com/${login_text:-user}/g" /overleaf/services/web/app/views/user/login.pug && \
RUN sed -iE "s/email@example.com/${login_text:-user}/g" /overleaf/services/web/app/views/user/login.pug && \
## Collaboration settings display (share project placeholder) | edit line 146
## share.pug file was removed in later versions
# sed -iE "s%placeholder=.*$%placeholder=\"${collab_text}\"%g" /overleaf/services/web/app/views/project/editor/share.pug && \

View File

@ -275,81 +275,79 @@ const AuthenticationController = {
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
oauth2Redirect(req, res, next) {
const redirectURI = encodeURIComponent(`${process.env.SHARELATEX_SITE_URL}/oauth/callback`)
const next = (
const authURL = (
process.env.OAUTH2_AUTHORIZATION_URL
+ `?response_type=code`
+ `&client_id=${process.env.OAUTH2_CLIENT_ID}`
+ `&redirect_uri=${redirectURI}`
+ `&scope=${process.env.OAUTH2_SCOPE ?? ""}` // TODO: state
)
res.redirect(next)
res.redirect(authURL)
},
async oauth2Callback(req, res, next) {
try {
const redirectURI = encodeURIComponent(`${process.env.SHARELATEX_SITE_URL}/oauth/callback`);
console.log("OAuth2 code", req.query.code)
const tokenResponse = await fetch(process.env.OAUTH2_TOKEN_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
"Accept": "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
client_id: process.env.OAUTH2_CLIENT_ID,
client_secret: process.env.OAUTH2_CLIENT_SECRET,
code: req.query.code,
redirect_uri: redirectURI,
redirect_uri: `${process.env.SHARELATEX_SITE_URL}/oauth/callback`,
})
})
const tokenData = await tokenResponse.json()
console.log("OAuth2 respond", JSON.stringify(tokenData)) // TODO: remove
console.log("OAuth2 accessToken", tokenData.access_token) // TODO: remove
console.log("OAuth2 respond", JSON.stringify(tokenData))
const profileResponse = await fetch(process.env.OAUTH2_PROFILE_URL, {
method: 'GET',
headers: {
"Accept": "application/json",
"Authorization": `Bearer ${tokenData.access_token}`,
"Content-Type": "application/json",
"Authorization": `Bearer ${tokenData.access_token}`
}
})
const profile = await profileResponse.json()
console.log("OAuth2 user info", JSON.stringify(profile.data))
console.log("OAuth2 user profile", JSON.stringify(profile))
const email = profile[process.env.OAUTH2_USER_ATTR_EMAIL ?? "email"]
const uid = profile[process.env.OAUTH2_USER_ATTR_UID ?? "uid"]
const firstname = profile?.[process.env.OAUTH2_USER_ATTR_FIRSTNAME] ?? email
const lastname = profile?.[process.env.OAUTH2_USER_ATTR_LASTNAME] ?? ""
const isAdmin = false // TODO: how to determine?
const lastname = process.env.OAUTH2_USER_ATTR_LASTNAME
? profile?.[process.env.OAUTH2_USER_ATTR_LASTNAME] ?? ""
: ""
const isAdmin = process.env.OAUTH2_USER_ATTR_IS_ADMIN
? !!profile?.[process.env.OAUTH2_USER_ATTR_IS_ADMIN] ?? false
: false
const query = { email }
User.findOne(query, (error, user) => {
const callback = (error, user) => {
if (error) {
console.log(error)
res.json({message: error});
} else {
console.log("OAuth user", JSON.stringify(user));
AuthenticationController.finishLogin(user, req, res, next);
}
const callback = (error, user) => {
if (error) {
res.json({message: error});
} else {
// console.log("real_user: ", user);
AuthenticationController.finishLogin(user, req, res, next);
}
}
AuthenticationManager.createIfNotExistAndLogin(
query,
user,
callback,
uid,
firstname,
lastname,
email,
isAdmin
)
})
}
AuthenticationManager.createIfNotFoundAndLogin(
query,
callback,
uid,
firstname,
lastname,
email,
isAdmin
)
} catch(e) {
console.log("Fails to access by OAuth2: " + String(e))
res.redirect("/login")
console.error("Fails to access by OAuth2: " + String(e))
}
},
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

View File

@ -184,6 +184,33 @@ const AuthenticationManager = {
callback(null, user, true)
},
createIfNotFoundAndLogin(
query,
callback,
uid,
firstname,
lastname,
mail,
isAdmin
) {
User.findOne(query, (error, user) => {
if (error) {
console.log(error)
}
AuthenticationManager.createIfNotExistAndLogin(
query,
user,
callback,
uid,
firstname,
lastname,
mail,
isAdmin
)
})
},
createIfNotExistAndLogin(
query,
user,
@ -195,10 +222,9 @@ const AuthenticationManager = {
isAdmin
) {
if (!user) {
//console.log('Creating User:' + JSON.stringify(query))
//create random pass for local userdb, does not get checked for ldap users during login
let pass = require("crypto").randomBytes(32).toString("hex")
//console.log('Creating User:' + JSON.stringify(query) + 'Random Pass' + pass)
const pass = require("crypto").randomBytes(32).toString("hex")
console.log('Creating User', { mail, uid, firstname, lastname, isAdmin, pass })
const userRegHand = require("../User/UserRegistrationHandler.js")
userRegHand.registerNewUser(
@ -228,6 +254,7 @@ const AuthenticationManager = {
}
) // end register user
} else {
console.log('User exists', { mail })
AuthenticationManager.login(user, "randomPass", callback)
}
},

View File

@ -16,13 +16,21 @@ block content
input(name='_csrf', type='hidden', value=csrfToken)
+formMessages()
.form-group
//- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//- input.form-control(
//- type='email',
//- name='email',
//- required,
//- placeholder='email@example.com',
//- autofocus="true"
//- )
input.form-control(
type='email',
name='email',
required,
placeholder='email@example.com',
autofocus="true"
)
//- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
.form-group
input.form-control(
type='password',
@ -38,8 +46,8 @@ block content
span(data-ol-inflight="idle") #{translate("login")}
span(hidden data-ol-inflight="pending") #{translate("logging_in")}…
a.pull-right(href='/user/password/reset') #{translate("forgot_your_password")}?
//- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.form-group.text-center(style="padding-top: 10px")
a.btn-block.login-btn(href="/oauth/redirect" style='padding-left: 0px')
| Log in via OAuth
//- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

View File

@ -1,6 +1,6 @@
/**
* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* Modified from 6408d15
* Modified from bf92436
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
*/
@ -27,7 +27,6 @@ const UserInfoController = require('./Features/User/UserInfoController')
const UserController = require('./Features/User/UserController')
const UserEmailsController = require('./Features/User/UserEmailsController')
const UserPagesController = require('./Features/User/UserPagesController')
const TutorialController = require('./Features/Tutorial/TutorialController')
const DocumentController = require('./Features/Documents/DocumentController')
const CompileManager = require('./Features/Compile/CompileManager')
const CompileController = require('./Features/Compile/CompileController')
@ -105,6 +104,10 @@ const rateLimiters = {
points: 10,
duration: 60,
}),
confirmUniversityDomain: new RateLimiter('confirm-university-domain', {
points: 1,
duration: 60,
}),
createProject: new RateLimiter('create-project', {
points: 20,
duration: 60,
@ -149,6 +152,10 @@ const rateLimiters = {
points: 30,
duration: 60,
}),
indexProjectReferences: new RateLimiter('index-project-references', {
points: 30,
duration: 60,
}),
miscOutputDownload: new RateLimiter('misc-output-download', {
points: 1000,
duration: 60 * 60,
@ -185,7 +192,7 @@ const rateLimiters = {
duration: 60,
}),
resendConfirmation: new RateLimiter('resend-confirmation', {
points: 1,
points: 10,
duration: 60,
}),
sendChatMessage: new RateLimiter('send-chat-message', {
@ -256,12 +263,12 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
AuthenticationController.addEndpointToLoginWhitelist('/register')
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
webRouter.get('/oauth/redirect', AuthenticationController.oauth2Redirect)
webRouter.get('/oauth/callback', AuthenticationController.oauth2Callback)
AuthenticationController.addEndpointToLoginWhitelist('/oauth/redirect')
AuthenticationController.addEndpointToLoginWhitelist('/oauth/callback')
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
webRouter.get('/oauth/redirect', AuthenticationController.oauth2Redirect)
webRouter.get('/oauth/callback', AuthenticationController.oauth2Callback)
AuthenticationController.addEndpointToLoginWhitelist('/oauth/redirect')
AuthenticationController.addEndpointToLoginWhitelist('/oauth/callback')
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
EditorRouter.apply(webRouter, privateApiRouter)
CollaboratorsRouter.apply(webRouter, privateApiRouter)
@ -433,12 +440,6 @@ AuthenticationController.addEndpointToLoginWhitelist('/oauth/callback')
TpdsController.getQueues
)
webRouter.post(
'/tutorial/:tutorialKey/complete',
AuthenticationController.requireLogin(),
TutorialController.completeTutorial
)
webRouter.get(
'/user/projects',
AuthenticationController.requireLogin(),
@ -734,6 +735,16 @@ AuthenticationController.addEndpointToLoginWhitelist('/oauth/callback')
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.proxyToHistoryApi
)
webRouter.post(
'/project/:Project_id/doc/:doc_id/version/:version_id/restore',
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
HistoryController.proxyToHistoryApi
)
webRouter.post(
'/project/:project_id/doc/:doc_id/restore',
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
HistoryController.restoreDocFromDeletedDoc
)
webRouter.post(
'/project/:project_id/restore_file',
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
@ -1082,6 +1093,12 @@ AuthenticationController.addEndpointToLoginWhitelist('/oauth/callback')
ChatController.sendMessage
)
webRouter.post(
'/project/:Project_id/references/index',
AuthorizationMiddleware.ensureUserCanReadProject,
RateLimiterMiddleware.rateLimit(rateLimiters.indexProjectReferences),
ReferencesController.index
)
webRouter.post(
'/project/:Project_id/references/indexAll',
AuthorizationMiddleware.ensureUserCanReadProject,
@ -1130,6 +1147,7 @@ AuthenticationController.addEndpointToLoginWhitelist('/oauth/callback')
)
publicApiRouter.post(
'/api/institutions/confirm_university_domain',
RateLimiterMiddleware.rateLimit(rateLimiters.confirmUniversityDomain),
AuthenticationController.requirePrivateApiAuth(),
InstitutionsController.confirmDomain
)
@ -1357,5 +1375,4 @@ AuthenticationController.addEndpointToLoginWhitelist('/oauth/callback')
webRouter.get('*', ErrorController.notFound)
}
module.exports = { initialize, rateLimiters }
module.exports = { initialize, rateLimiters }