@mntu/nestjs-ldap
Version:
NestJS library to access LDAP
496 lines (418 loc) • 11 kB
text/typescript
//#region Imports NPM
import type { LoggerService } from '@nestjs/common';
import type { ModuleMetadata, Type } from '@nestjs/common/interfaces';
import type { ClientOptions, SearchEntryObject } from 'ldapjs';
import type { Redis } from 'ioredis';
//#endregion
export const LDAP_SYNC = 'LDAP_SYNC';
export const LDAP_OPTIONS = 'LDAP_OPTIONS';
export type Scope = 'base' | 'one' | 'sub';
export interface LoggerContext {
[key: string]: string | unknown | null;
}
export interface LdapAddEntry {
uid: string;
/**
* Common name
*/
cn?: string;
displayName?: string;
name?: string;
comment?: Record<string, string> | string;
thumbnailPhoto?: Buffer;
objectClass: string | string[];
[p: string]:
| undefined
| string
| string[]
| Record<string, string>
| Buffer;
}
export interface LdapModifyEntry {
uid: string;
[p: string]:
| undefined
| string
| string[]
| Record<string, string>
| Buffer;
}
export interface LdapResponseObject
extends Pick<SearchEntryObject, 'dn' | 'controls'> {
/**
* Domain of this user
*/
loginDomain: string;
/**
* Distinguished name
*/
distinguishedName: string;
/**
* Common name
*/
cn: string;
/**
* Description
*/
description: string;
/**
* Display name
*/
displayName: string;
/**
* Name
*/
name: string;
// Object category
objectCategory: string;
objectClass: string[];
// Object GUID - ID in ldap
objectGUID: string;
/**
* SAM account name
*/
sAMAccountName: string;
sAMAccountType: string;
whenChanged: Date;
whenCreated: Date;
}
export type LdapResponseGroup = LdapResponseObject;
export interface LdapResponseUser extends LdapResponseObject {
/**
* Ldap response groups
*/
groups: LdapResponseGroup[];
/**
* Country
*/
c: string;
/**
* Country expanded
*/
co: string;
/**
* Comment
*/
comment: string;
/**
* Company
*/
company: string;
/**
* Country code
*/
countryCode: string;
/**
* Department name
*/
department: string;
/**
* Employee ID
*/
employeeID: string;
employeeNumber: string;
employeeType: string;
/**
* Given name
*/
givenName: string;
/**
* Additional flags
*/
flags: string;
/**
* Locality
*/
l: string;
// Lockout time
lockoutTime: string;
// E-mail
mail: string;
otherMailbox: string[];
// Member of groups
memberOf: string[];
// middle name
middleName: string;
// Mobile phone
mobile: string;
// Manager Profile ?
manager: string;
// Other telephones
otherTelephone: string[];
// Postal code
postalCode: string;
/**
* Office name
*/
physicalDeliveryOfficeName: string;
/**
* Family name
*/
sn: string;
/**
* Region
*/
st: string;
/**
* Street address
*/
streetAddress: string;
/**
* Telephone number
*/
telephoneNumber: string;
/**
* Fax number
*/
facsimileTelephoneNumber: string;
/**
* Thumbnail photo
*/
thumbnailPhoto: string;
/**
* Jpeg photo
*/
jpegPhoto: string[];
carLicense: string;
/**
* Work title
*/
title: string;
userAccountControl: string;
wWWHomePage: string;
userPrincipalName: string;
badPasswordTime: Date;
badPwdCount: number;
// Logon, logoff
logonCount: number;
lastLogoff: Date;
lastLogon: Date;
lastLogonTimestamp: Date;
pwdLastSet: Date;
/* Active Directory */
'msDS-cloudExtensionAttribute1'?: string;
'msDS-cloudExtensionAttribute2'?: string;
/* In our AD: Date of birth */
'msDS-cloudExtensionAttribute3'?: string;
'msDS-cloudExtensionAttribute4'?: string;
'msDS-cloudExtensionAttribute5'?: string;
'msDS-cloudExtensionAttribute6'?: string;
'msDS-cloudExtensionAttribute7'?: string;
'msDS-cloudExtensionAttribute8'?: string;
'msDS-cloudExtensionAttribute9'?: string;
'msDS-cloudExtensionAttribute10'?: string;
'msDS-cloudExtensionAttribute11'?: string;
'msDS-cloudExtensionAttribute12'?: string;
/* In our AD: access card (pass) */
'msDS-cloudExtensionAttribute13'?: string;
'msDS-cloudExtensionAttribute14'?: string;
'msDS-cloudExtensionAttribute15'?: string;
'msDS-cloudExtensionAttribute16'?: string;
'msDS-cloudExtensionAttribute17'?: string;
'msDS-cloudExtensionAttribute18'?: string;
'msDS-cloudExtensionAttribute19'?: string;
'msDS-cloudExtensionAttribute20'?: string;
}
interface GroupSearchFilterFunction {
/**
* Construct a group search filter from user object
*
* @param user The user retrieved and authenticated from LDAP
*/
(user: LdapResponseUser): string;
}
export interface LdapDomainsConfig extends ClientOptions {
/**
* Name string: EXAMPLE.COM
*/
name: string;
/**
* Admin connection DN, e.g. uid=myapp,ou=users,dc=example,dc=org.
* If not given at all, admin client is not bound. Giving empty
* string may result in anonymous bind when allowed.
*
* Note: Not passed to ldapjs, it would bind automatically
*/
bindDN: string;
/**
* Password for bindDN
*/
bindCredentials: string;
/**
* Property of the LDAP user object to use when binding to verify
* the password. E.g. name, email. Default: dn
*/
bindProperty?: 'dn';
/**
* The base DN from which to search for users by username.
* E.g. ou=users,dc=example,dc=org
*/
searchBase: string;
/**
* LDAP search filter with which to find a user by username, e.g.
* (uid={{username}}). Use the literal {{username}} to have the
* given username interpolated in for the LDAP search.
*/
searchFilter: string;
/**
* Scope of the search. Default: 'sub'
*/
searchScope?: Scope;
/**
* Array of attributes to fetch from LDAP server. Default: all
*/
searchAttributes?: string[];
/**
* LDAP synchronization
*/
hideSynchronization?: boolean;
/**
* LDAP search filter with synchronization.
*/
searchFilterAllUsers?: string;
/**
* Scope of the search. Default: 'sub'
*/
searchScopeAllUsers?: Scope;
/**
* Array of attributes to fetch from LDAP server. Default: all
*/
searchAttributesAllUsers?: string[];
/**
* The base DN from which to search for groups. If defined,
* also groupSearchFilter must be defined for the search to work.
*/
groupSearchBase?: string;
/**
* LDAP search filter for groups. Place literal {{dn}} in the filter
* to have it replaced by the property defined with `groupDnProperty`
* of the found user object. Optionally you can also assign a
* function instead. The found user is passed to the function and it
* should return a valid search filter for the group search.
*/
groupSearchFilter?: string | GroupSearchFilterFunction;
searchFilterAllGroups?: string;
/**
* Scope of the search. Default: sub
*/
groupSearchScope?: Scope;
/**
* Array of attributes to fetch from LDAP server. Default: all
*/
groupSearchAttributes?: string[];
/**
* The property of user object to use in '{{dn}}' interpolation of
* groupSearchFilter. Default: 'dn'
*/
groupDnProperty?: string;
/**
* Set to true to add property '_raw' containing the original buffers
* to the returned user object. Useful when you need to handle binary
* attributes
*/
includeRaw?: boolean;
timeLimit?: number;
sizeLimit?: number;
/**
* Where new objects (contacts, users) to place
*/
newObject?: string;
}
export interface LdapModuleOptions {
/**
* Domains config
*/
domains: LdapDomainsConfig[];
/**
* Logging options
*/
logger: LoggerService;
/**
* If true, then up to 100 credentials at a time will be cached for
* 5 minutes.
*/
cache?: Redis;
cacheUrl?: string;
cacheTtl?: number;
}
export interface LdapOptionsFactory {
createLdapOptions(): Promise<LdapModuleOptions> | LdapModuleOptions;
}
export interface LdapModuleAsyncOptions
extends Pick<ModuleMetadata, 'imports'> {
useExisting?: Type<LdapOptionsFactory>;
useClass?: Type<LdapOptionsFactory>;
useFactory?: (
...args: any[]
) => Promise<LdapModuleOptions> | LdapModuleOptions;
inject?: any[];
}
export const ldapADattributes = [
'thumbnailPhoto;binary',
// 'jpegPhoto;binary',
'objectGUID;binary',
// 'objectSid;binary',
'c',
'cn',
'co',
'codePage',
'comment',
'company',
'countryCode',
'department',
'description',
'displayName',
'distinguishedName',
'dn',
'employeeID',
'flags',
'givenName',
'l',
'mail',
'memberOf',
'middleName',
'manager',
'mobile',
'name',
'objectCategory',
'objectClass',
'otherMailbox',
'otherTelephone',
'postalCode',
'primaryGroupID',
'sAMAccountName',
'sAMAccountType',
'sn',
'st',
'streetAddress',
'telephoneNumber',
'title',
'wWWHomePage',
'userAccountControl',
'whenChanged',
'whenCreated',
'msDS-cloudExtensionAttribute1',
'msDS-cloudExtensionAttribute2',
'msDS-cloudExtensionAttribute3',
'msDS-cloudExtensionAttribute4',
'msDS-cloudExtensionAttribute5',
'msDS-cloudExtensionAttribute6',
'msDS-cloudExtensionAttribute7',
'msDS-cloudExtensionAttribute8',
'msDS-cloudExtensionAttribute9',
'msDS-cloudExtensionAttribute10',
'msDS-cloudExtensionAttribute11',
'msDS-cloudExtensionAttribute12',
'msDS-cloudExtensionAttribute13',
'msDS-cloudExtensionAttribute14',
'msDS-cloudExtensionAttribute15',
'msDS-cloudExtensionAttribute16',
'msDS-cloudExtensionAttribute17',
'msDS-cloudExtensionAttribute18',
'msDS-cloudExtensionAttribute19',
'msDS-cloudExtensionAttribute20',
];
export interface LDAPCache {
user: LdapResponseUser;
password: string;
}