Fork of node-ldapauth-fork targeted towards use with an Active Directory domain.
import ADAuth from 'adauth'
const options = {
url: 'ldaps://corp.example.com:636',
domainDN: 'dc=example,dc=com',
}
const auth = await ADAuth.create(options)
// or
const auth = new ADAuth(options)
await auth.initialise()
try {
const user = await auth.authenticate(username, password)
} catch (error) {
console.error('Authentication failed: ', error)
}
await auth.dispose()ADAuth inherits from EventEmitter.
$ npm install adauth
Required client options:
url- LLDAP url for the AD domain controller, e.g.ldaps://corp.example.com:636domainDN- The root DN of the AD domain, e.g.dc=corp,dc=example,dc=com
searchBase- The base DN from which to search for users by username. E.g.ou=users,dc=example,dc=comsearchFilterByDN- Optional, default(&(objectCategory=user)(objectClass=user)(distinguishedName={{dn}})). Search filter with which to find a user by FQDN.searchFilterByUPN- Optional, default(&(objectCategory=user)(objectClass=user)(userPrincipalName={{upn}})). Search filter with which to find a user by UPN. ([email protected])searchFilterBySAN- Optional, default(&(objectCategory=user)(objectClass=user)(samAccountName={{username}})). Search filter with which to find a user by their old-format Windows username.searchAttributes- Optional, default all. Array of attributes to fetch from LDAP server.bindProperty- Optional, defaultdn. Property of the LDAP user object to use when binding to verify the password. E.g.name,emailsearchScope- Optional, defaultsub. Scope of the search, one ofbase,one, orsub.
adauth can look for valid user groups too. Related options:
groupSearchBase- Optional. The base DN from which to search for groups. If defined, alsogroupSearchFiltermust be defined for the search to work.groupSearchFilter- Optional. LDAP search filter for groups. Place literal{{dn}}in the filter to have it replaced by the property defined withgroupDnPropertyof the found user object.{{username}}is also available and will be replaced with theuidof the found user. This is useful for example to filter PosixGroups bymemberUid. 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.groupSearchAttributes- Optional, default all. Array of attributes to fetch from LDAP server.groupDnProperty- Optional, defaultdn. The property of user object to use in{{dn}}interpolation ofgroupSearchFilter.groupSearchScope- Optional, defaultsub.
Other adauth options:
includeRaw- Optional, default false. Set to true to add property_rawcontaining the original buffers to the returned user object. Useful when you need to handle binary attributescache- Optional, default false. If true, then up to 100 credentials at a time will be cached for 5 minutes.log- Bunyan logger instance, optional. If given this will result in TRACE-level error logging for component:ldapauth. The logger is also passed forward to ldapjs.
Optional ldapjs options, see ldapjs documentation:
tlsOptions- Needed for TLS connection. See Node.js documentationsocketPathtimeoutconnectTimeoutidleTimeoutstrictDNqueueSizequeueTimeoutqueueDisable
The AD authentication flow is usually:
- Bind the client using the given username and credentials to verify the given password
- Use the client to search for the user by substituting
{{username}}from the appropriatesearchFilter - Search for the groups of the user
import basicAuth from 'basic-auth'
import ADAuth from 'adauth'
const ad = await ADAuth.create({
url: "ldaps://corp.example.com:636",
domainDN: "DC=example,DC=com",
searchBase: "OU=Users,OU=MyBusiness,DC=example,DC=com",
tlsOptions: {
ca: "./example-ca.cer",
},
reconnect: true,
})
const rejectBasicAuth = res => {
res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="Example"')
res.end('Access denied')
}
const basicAuthMiddleware = (req, res, next) => {
const credentials = basicAuth(req)
if (!credentials) {
return rejectBasicAuth(res)
}
ad.authenticate(credentials.name, credentials.pass)
.then(user => {
req.user = user
next()
})
.catch(error => rejectBasicAuth(res))
})
}MIT