@sync-in/server
Version:
The secure, open-source platform for file storage, sharing, collaboration, and sync
185 lines (184 loc) • 8.44 kB
JavaScript
/*
* Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
* This file is part of Sync-in | The open source file sync and share solution
* See the LICENSE file for licensing details
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "AuthMethodLdapService", {
enumerable: true,
get: function() {
return AuthMethodLdapService;
}
});
const _common = require("@nestjs/common");
const _ldapts = require("ldapts");
const _appconstants = require("../../../app.constants");
const _user = require("../../../applications/users/constants/user");
const _adminusersmanagerservice = require("../../../applications/users/services/admin-users-manager.service");
const _usersmanagerservice = require("../../../applications/users/services/users-manager.service");
const _functions = require("../../../common/functions");
const _configenvironment = require("../../../configuration/config.environment");
function _ts_decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function _ts_metadata(k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}
let AuthMethodLdapService = class AuthMethodLdapService {
async validateUser(loginOrEmail, password, ip) {
let user = await this.usersManager.findUser(loginOrEmail, false);
if (user) {
if (user.isGuest) {
// allow guests to be authenticated from db & check if current user is defined as active
return this.usersManager.logUser(user, password, ip);
}
if (!user.isActive) {
this.logger.error(`${this.validateUser.name} - user *${user.login}* is locked`);
throw new _common.HttpException('Account locked', _common.HttpStatus.FORBIDDEN);
}
}
const entry = await this.checkAuth(loginOrEmail, password);
if (entry === false) {
if (user) {
this.usersManager.updateAccesses(user, ip, false).catch((e)=>this.logger.error(`${this.validateUser.name} : ${e}`));
}
return null;
} else if (!entry.mail || !entry.uid) {
this.logger.error(`${this.validateUser.name} - ${loginOrEmail} : some ldap fields are missing => (${JSON.stringify(entry)})`);
return null;
}
const identity = {
login: entry.uid,
email: entry.mail,
password: password,
...(0, _functions.splitFullName)(entry.cn)
};
user = await this.updateOrCreateUser(identity, user);
this.usersManager.updateAccesses(user, ip, true).catch((e)=>this.logger.error(`${this.validateUser.name} : ${e}`));
return user;
}
async checkAuth(uid, password) {
const servers = _configenvironment.configuration.auth.ldap.servers;
const bindUserDN = `${_configenvironment.configuration.auth.ldap.loginAttribute}=${uid},${_configenvironment.configuration.auth.ldap.baseDN}`;
let client;
let error;
for (const s of servers){
client = new _ldapts.Client({
...this.clientOptions,
url: s
});
try {
await client.bind(bindUserDN, password);
return await this.checkAccess(client, uid);
} catch (e) {
if (e.errors?.length) {
for (const err of e.errors){
this.logger.warn(`${this.checkAuth.name} - ${uid} : ${err}`);
error = err;
}
} else {
error = e;
this.logger.warn(`${this.checkAuth.name} - ${uid} : ${e}`);
}
if (error instanceof _ldapts.InvalidCredentialsError) {
return false;
}
} finally{
await client.unbind();
}
}
if (error && _appconstants.CONNECT_ERROR_CODE.has(error.code)) {
throw new _common.HttpException('Authentication service connection error', _common.HttpStatus.INTERNAL_SERVER_ERROR);
}
return false;
}
async checkAccess(client, uid) {
const searchFilter = `(&(${_configenvironment.configuration.auth.ldap.loginAttribute}=${uid})${_configenvironment.configuration.auth.ldap.filter || ''})`;
try {
const { searchEntries } = await client.search(_configenvironment.configuration.auth.ldap.baseDN, {
scope: 'sub',
filter: searchFilter,
attributes: this.entryAttributes
});
for (const entry of searchEntries){
if (entry[_configenvironment.configuration.auth.ldap.loginAttribute] === uid) {
if (Array.isArray(entry.mail)) {
// handles the case of multiple emails, keep the first
entry.mail = entry.mail[0];
}
return entry;
}
}
return false;
} catch (e) {
this.logger.warn(`${this.checkAccess.name} - ${uid} : ${e}`);
return false;
}
}
async updateOrCreateUser(identity, user) {
if (user === null) {
return this.adminUsersManager.createUserOrGuest(identity, _user.USER_ROLE.USER);
} else {
if (identity.login !== user.login) {
this.logger.error(`${this.updateOrCreateUser.name} - user id mismatch : ${identity.login} !== ${user.login}`);
throw new _common.HttpException('Account matching error', _common.HttpStatus.FORBIDDEN);
}
// check if user information has changed
const identityHasChanged = Object.fromEntries((await Promise.all(Object.keys(identity).map(async (key)=>{
if (key === 'password') {
const isSame = await (0, _functions.comparePassword)(identity[key], user.password);
return isSame ? null : [
key,
identity[key]
];
}
return identity[key] !== user[key] ? [
key,
identity[key]
] : null;
}))).filter(Boolean));
if (Object.keys(identityHasChanged).length > 0) {
try {
await this.adminUsersManager.updateUserOrGuest(user.id, identityHasChanged);
if (identityHasChanged?.password) {
delete identityHasChanged.password;
}
Object.assign(user, identityHasChanged);
} catch (e) {
this.logger.warn(`${this.updateOrCreateUser.name} - unable to update user *${user.login}* : ${e}`);
}
}
await user.makePaths();
return user;
}
}
constructor(usersManager, adminUsersManager){
this.usersManager = usersManager;
this.adminUsersManager = adminUsersManager;
this.logger = new _common.Logger(AuthMethodLdapService.name);
this.entryAttributes = [
'uid',
'mail',
'cn'
];
this.clientOptions = {
timeout: 6000,
connectTimeout: 6000,
url: ''
};
}
};
AuthMethodLdapService = _ts_decorate([
(0, _common.Injectable)(),
_ts_metadata("design:type", Function),
_ts_metadata("design:paramtypes", [
typeof _usersmanagerservice.UsersManager === "undefined" ? Object : _usersmanagerservice.UsersManager,
typeof _adminusersmanagerservice.AdminUsersManager === "undefined" ? Object : _adminusersmanagerservice.AdminUsersManager
])
], AuthMethodLdapService);
//# sourceMappingURL=auth-method-ldap.service.js.map