19a20,25 > // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > const fs = require("fs") > const { Client } = require("ldapts") > const ldapEscape = require("ldap-escape") > // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< > 84a91,100 > // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > _checkUserPassword2(query, password, callback) { > // leave original _checkUserPassword untouched, because it will be called by > // setUserPasswordInV2 (e.g. UserRegistrationHandler.js ) > User.findOne(query, (error, user) => { > AuthenticationManager.authUserObj(error, user, query, password, callback) > }) > }, > // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< > 90c106,108 < AuthenticationManager._checkUserPassword( --- > // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > AuthenticationManager._checkUserPassword2( > // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 153a172,451 > > // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > /** > * login with any password > */ > login(user, password, callback) { > 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, > callback, > uid, > firstname, > lastname, > mail, > isAdmin > ) { > if (!user) { > //create random pass for local userdb, does not get checked for ldap users during login > 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( > { > email: mail, > first_name: firstname, > last_name: lastname, > password: pass, > }, > function (error, user, setNewPasswordUrl) { > if (error) { > console.log(error) > } > user.email = mail > user.isAdmin = isAdmin > user.emails[0].confirmedAt = Date.now() > user.save() > //console.log('user %s added to local library: ', mail) > User.findOne(query, (error, user) => { > if (error) { > console.log(error) > } > if (user && user.hashedPassword) { > AuthenticationManager.login(user, "randomPass", callback) > } > }) > } > ) // end register user > } else { > console.log('User exists', { mail }) > AuthenticationManager.login(user, "randomPass", callback) > } > }, > > authUserObj(error, user, query, password, callback) { > if (process.env.ALLOW_EMAIL_LOGIN && user && user.hashedPassword) { > console.log("email login for existing user " + query.email) > // check passwd against local db > bcrypt.compare(password, user.hashedPassword, function (error, match) { > if (match) { > console.log("Local user password match") > _metricsForSuccessfulPasswordMatch(password) > //callback(null, user, match) > AuthenticationManager.login(user, "randomPass", callback) > } else { > console.log("Local user password mismatch, trying LDAP") > // check passwd against ldap > AuthenticationManager.ldapAuth( > query, > password, > AuthenticationManager.createIfNotExistAndLogin, > callback, > user > ) > } > }) > } else { > // No local passwd check user has to be in ldap and use ldap credentials > AuthenticationManager.ldapAuth( > query, > password, > AuthenticationManager.createIfNotExistAndLogin, > callback, > user > ) > } > return null > }, > > async ldapAuth( > query, > password, > onSuccessCreateUserIfNotExistent, > callback, > user > ) { > const client = fs.existsSync(process.env.LDAP_SERVER_CACERT) > ? new Client({ > url: process.env.LDAP_SERVER, > tlsOptions: { > ca: [fs.readFileSync(process.env.LDAP_SERVER_CACERT)], > }, > }) > : new Client({ > url: process.env.LDAP_SERVER, > }) > > const ldap_reader = process.env.LDAP_BIND_USER > const ldap_reader_pass = process.env.LDAP_BIND_PW > const ldap_base = process.env.LDAP_BASE > > var mail = query.email > var uid = query.email.split("@")[0] > var firstname = "" > var lastname = "" > var isAdmin = false > var userDn = "" > > //replace all appearences of %u with uid and all %m with mail: > const replacerUid = new RegExp("%u", "g") > const replacerMail = new RegExp("%m", "g") > const filterstr = process.env.LDAP_USER_FILTER.replace( > replacerUid, > ldapEscape.filter`${uid}` > ).replace(replacerMail, ldapEscape.filter`${mail}`) //replace all appearances > // check bind > try { > if (process.env.LDAP_BINDDN) { > //try to bind directly with the user trying to log in > userDn = process.env.LDAP_BINDDN.replace( > replacerUid, > ldapEscape.filter`${uid}` > ).replace(replacerMail, ldapEscape.filter`${mail}`) > await client.bind(userDn, password) > } else { > // use fixed bind user > await client.bind(ldap_reader, ldap_reader_pass) > } > } catch (ex) { > if (process.env.LDAP_BINDDN) { > console.log("Could not bind user: " + userDn) > } else { > console.log( > "Could not bind LDAP reader: " + ldap_reader + " err: " + String(ex) > ) > } > return callback(null, null) > } > > // get user data > try { > const { searchEntries, searchRef } = await client.search(ldap_base, { > scope: "sub", > filter: filterstr, > }) > await searchEntries > console.log(JSON.stringify(searchEntries)) > if (searchEntries[0]) { > mail = searchEntries[0].mail > uid = searchEntries[0].uid > firstname = searchEntries[0].givenName > lastname = searchEntries[0].sn > if (!process.env.LDAP_BINDDN) { > //dn is already correctly assembled > userDn = searchEntries[0].dn > } > console.log( > `Found user: ${mail} Name: ${firstname} ${lastname} DN: ${userDn}` > ) > } > } catch (ex) { > console.log( > "An Error occured while getting user data during ldapsearch: " + > String(ex) > ) > await client.unbind() > return callback(null, null) > } > > try { > // if admin filter is set - only set admin for user in ldap group > // does not matter - admin is deactivated: managed through ldap > if (process.env.LDAP_ADMIN_GROUP_FILTER) { > const adminfilter = process.env.LDAP_ADMIN_GROUP_FILTER.replace( > replacerUid, > ldapEscape.filter`${uid}` > ).replace(replacerMail, ldapEscape.filter`${mail}`) > adminEntry = await client.search(ldap_base, { > scope: "sub", > filter: adminfilter, > }) > await adminEntry > //console.log('Admin Search response:' + JSON.stringify(adminEntry.searchEntries)) > if (adminEntry.searchEntries[0]) { > console.log("is Admin") > isAdmin = true > } > } > } catch (ex) { > console.log( > "An Error occured while checking for admin rights - setting admin rights to false: " + > String(ex) > ) > isAdmin = false > } finally { > await client.unbind() > } > if (mail == "" || userDn == "") { > console.log( > "Mail / userDn not set - exit. This should not happen - please set mail-entry in ldap." > ) > return callback(null, null) > } > > if (!process.env.BINDDN) { > //since we used a fixed bind user to obtain the correct userDn we need to bind again to authenticate > try { > await client.bind(userDn, password) > } catch (ex) { > console.log("Could not bind User: " + userDn + " err: " + String(ex)) > return callback(null, null) > } finally { > await client.unbind() > } > } > //console.log('Logging in user: ' + mail + ' Name: ' + firstname + ' ' + lastname + ' isAdmin: ' + String(isAdmin)) > // we are authenticated now let's set the query to the correct mail from ldap > query.email = mail > User.findOne(query, (error, user) => { > if (error) { > console.log(error) > } > if (user && user.hashedPassword) { > //console.log('******************** LOGIN ******************') > AuthenticationManager.login(user, "randomPass", callback) > } else { > onSuccessCreateUserIfNotExistent( > query, > user, > callback, > uid, > firstname, > lastname, > mail, > isAdmin > ) > } > }) > }, > // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<