Files
overleaf-cep/services/web/modules/authentication/ldap/app/src/LDAPModuleManager.mjs

109 lines
3.9 KiB
JavaScript

import logger from '@overleaf/logger'
import passport from 'passport'
import { Strategy as LDAPStrategy } from 'passport-ldapauth'
import Settings from '@overleaf/settings'
import PermissionsManager from '../../../../../app/src/Features/Authorization/PermissionsManager.js'
import { readFilesContentFromEnv, numFromEnv, boolFromEnv } from '../../../utils.mjs'
import LDAPAuthenticationController from './LDAPAuthenticationController.mjs'
import fetchLDAPContacts from './LDAPContacts.mjs'
const LDAPModuleManager = {
initSettings() {
Settings.ldap = {
enable: true,
placeholder: process.env.OVERLEAF_LDAP_PLACEHOLDER || 'Username',
attEmail: process.env.OVERLEAF_LDAP_EMAIL_ATT || 'mail',
attFirstName: process.env.OVERLEAF_LDAP_FIRST_NAME_ATT,
attLastName: process.env.OVERLEAF_LDAP_LAST_NAME_ATT,
attName: process.env.OVERLEAF_LDAP_NAME_ATT,
attAdmin: process.env.OVERLEAF_LDAP_IS_ADMIN_ATT,
valAdmin: process.env.OVERLEAF_LDAP_IS_ADMIN_ATT_VALUE,
updateUserDetailsOnLogin: boolFromEnv(process.env.OVERLEAF_LDAP_UPDATE_USER_DETAILS_ON_LOGIN),
}
},
passportSetup(passport, callback) {
const ldapOptions = {
url: process.env.OVERLEAF_LDAP_URL,
bindDN: process.env.OVERLEAF_LDAP_BIND_DN || "",
bindCredentials: process.env.OVERLEAF_LDAP_BIND_CREDENTIALS || "",
bindProperty: process.env.OVERLEAF_LDAP_BIND_PROPERTY,
searchBase: process.env.OVERLEAF_LDAP_SEARCH_BASE,
searchFilter: process.env.OVERLEAF_LDAP_SEARCH_FILTER,
searchScope: process.env.OVERLEAF_LDAP_SEARCH_SCOPE || 'sub',
searchAttributes: JSON.parse(process.env.OVERLEAF_LDAP_SEARCH_ATTRIBUTES || '[]'),
cache: boolFromEnv(process.env.OVERLEAF_LDAP_CACHE),
timeout: numFromEnv(process.env.OVERLEAF_LDAP_TIMEOUT),
connectTimeout: numFromEnv(process.env.OVERLEAF_LDAP_CONNECT_TIMEOUT),
starttls: boolFromEnv(process.env.OVERLEAF_LDAP_STARTTLS),
tlsOptions: {
ca: readFilesContentFromEnv(process.env.OVERLEAF_LDAP_TLS_OPTS_CA_PATH),
rejectUnauthorized: boolFromEnv(process.env.OVERLEAF_LDAP_TLS_OPTS_REJECT_UNAUTH),
}
}
try {
passport.use(
new LDAPStrategy(
{
server: ldapOptions,
passReqToCallback: true,
usernameField: 'email',
passwordField: 'password',
handleErrorsAsFailures: true,
},
LDAPAuthenticationController.doPassportLogin
)
)
callback(null)
} catch (error) {
callback(error)
}
},
async getContacts(userId, contacts, callback) {
try {
const newContacts = await fetchLDAPContacts(userId, contacts)
callback(null, newContacts)
} catch (error) {
callback(error)
}
},
initPolicy() {
try {
PermissionsManager.registerCapability('change-password', { default : true })
PermissionsManager.registerCapability('use-ai', { default : false })
} catch (error) {
logger.info({}, error.message)
}
const ldapPolicyValidator = async ({ user, subscription }) => {
// If user is not logged in, user.externalAuth is undefined,
// in this case allow to change password if the user has a hashedPassword
return user.externalAuth === 'ldap' || (user.externalAuth === undefined && !user.hashedPassword)
}
try {
PermissionsManager.registerPolicy(
'ldapPolicy',
{ 'change-password' : false },
{ validator: ldapPolicyValidator }
)
} catch (error) {
logger.info({}, error.message)
}
},
getGroupPolicyForUser(user, callback) {
PermissionsManager.promises.getUserValidationStatus({
user,
groupPolicy : { 'ldapPolicy' : true },
subscription : null
}).then(userValidationMap => {
let groupPolicy = Object.fromEntries(userValidationMap)
callback(null, { groupPolicy })
}).catch(error => {
callback(error)
})
},
}
export default LDAPModuleManager