LDAP Login
Provides an easy way to implement a login system based in LDAP and JWT.
Features
- Auth manager to authenticate against LDAP server with painless configuration.
- JSON Web Tokens integration (when your user is validated in LDAP server, a token is generated).
- Default user provider: You can use a predefined user provider based in LDAP.
- Customization: You can create your own providers to retrieve user info even out of LDAP server.
Installation
npm install ldap-login
Additional configuration for development
To run the test suite:
docker-compose up -d npm run test
To compile the module
npm run build
Big picture
ldap-login handle three important concepts:
Auth manager
A class used to encapsulate the authentication logic and provide an interface to validate a user. In this library it accomplishes this interface (I use here TS just for documentation purposes; the code in NPM is pure JS):
Of course we can create new AuthManagers, but for now, this is not the purpose of this library; it just provides LdapAuthManager and you can require it by doing this:
User provider
A class used to encapsulate user retrievement and role assigment; in this library it provides this interface:
Obviously User class can be different depending on your application behaviour, ldap-login provides the following User class, but you can provide your own (later we will explain how):
// It is created with TS, but obviusly yo can use a vanilla JS class
Security class
This class receive an AuthenticatorManager and UserProvider and put them together to perform the whole login process.
const Security = const security = manager: ldapAuthManager // Instange of LdapAuthManager with configuration values binded provider: LdapUserProvider // The user provider class (NOT INSTANCE) providerOptions: ldapUserProviderCnf // Security will instantiate the user provider class with this attributes
A quick look to exposed modules
Ldap-login exposes the following components:
const Security UserProvider LdapAuthManager LdapUserProvider Roles User SecurityMiddleware } =
- Security: Class to compose UserProvider and AuthManager interaction.
- UserProvider: Class to retrieve instances of User class. It must be extended to provide your own UserProvider implementation. You can treat it as an abstract class.
- LdapAuthManager: A class to handle login by configurated LDAP server.
- Roles: A list of roles defined by default for LdapUserProvider in this library.
- User: Default user model, you can extend it.
- SecurityMiddleware: Middlewares to use with Express.
Usage
The following example uses a predefined UserProvider in login-ldap library. It uses two specific objects (LDAP's organizationalRole) to assign roles to user. These two object must exist in your LDAP's database and must be referenced by config params 'roleUserDn' and 'roleAdminDn'. For example:
# LDIF with these two organizational roles as example
# jvc and admin users remains to admin role and jvc remains to user role too
dn: cn=admin,dc=genealogy,dc=my-company,dc=com
cn: admin
objectclass: organizationalRole
objectclass: top
roleoccupant: cn=jvc,ou=users,dc=my-company,dc=com
roleoccupant: cn=admin,dc=my-company,dc=com
dn: cn=user,dc=genealogy,dc=my-company,dc=com
cn: user
objectclass: organizationalRole
objectclass: top
roleoccupant: cn=jvc,ou=users,dc=my-company,dc=com
Read here a complete example schema.
You must use organizationalRole and roleoccupant if you want to use the predefined user provider, otherwise you can create your own (read 'Customization' section).
Basic login
To login by specified LDAP server you just need to do:
// src/security.js // I will use this file name in following code snippets // Module requirement------------------------------------------------------ const LdapAuthManager LdapUserProvider Security = // Module configuration (change it with your server credentials)----------- // With the following configuration a valid user could be cn=jvc,dc=my-company,dc=comconst ldapAuthManager = url: 'ldap://127.0.0.1:389' baseDn: 'dc=my-company,dc=com' // Base domain. Your user must be in a lower level idKey: 'cn' // Key user as username // If you want to use the predefined user provider you should provide a configuration like this:const ldapUserProviderCnf = roleUserDn: 'cn=user,dc=genealogy,dc=my-company,dc=com' // Role object in LDAP to store basic users roleAdminDn: 'cn=admin,dc=genealogy,dc=my-company,dc=com' // Role object in LDAP to store admin users ldapAdminLogin: 'cn=admin,dc=my-company,dc=com' // I recommend a READ ONLY admin ldapAdminPassword: 'admin' jwtPrivateKey: 'XXXXXXXX' // This key will be used to generate Tokens jwtExpiration: 60 * 60 const ldap = manager: ldapAuthManager provider: LdapUserProvider providerOptions: ldapUserProviderCnf moduleexports = ldap
Now you can use this module:
// index.js // F.Ex.const ldap = ldap
How to use it in a Express application
// index.js //F. Ex. const express = const bodyParser = const SecurityMiddleware Roles = // Use env vars could be a good idea to configure your auth provider and middleware// In the previous example (basic login) we've harcoded the vars. You can use env vars instead.const security = jwtPrivateKey: processenvJWT_PRIVATE_KEY const app = app // Here we are using the configuration in previous example (basic login) ./security.js fileconst ldap = // This code provides an endpoint to login by user and passwordapp app
IMPORTANT! You need to use 'authorization' header to send previously generated query. Here you have an example with curl:
# Request to get a User with token curl -X POST http://localhost:3000/auth \-H "Content-Type: application/json" \-d '{"login": "admin", "password": "admin"}'# Response }, "username":"admin", "description":"LDAP administrator", "token":"eyJhbGciOiJIUz...", "roles":[ "ROLE_USER", "ROLE_ADMIN" ]} # Now you can use the token to access to secure endpoints curl http://localhost:3000/my-endpoint -H "authorization: eyJhbGc..."
Customization
In the examples above we've used the predefined application functionality; a UserProvider prepared to retrieve user data from LDAP user and assign two different roles (ROLE_USER or ROLE_ADMIN) depending on LDAP's class organizationalRole and its field 'roleoccupant'. Obviously, this is a very specific application behaviour, and probably you will need to use a different strategy to get user information (for example from your database) and role assignment (ADMIN and USER could not be enough).
Creating your own user provider
const UserProvider User = { const anotherCustomParam authManager jwtPrivateKey jwtExpiration } = config superjwtPrivateKey jwtExpiration thisanotherCustomParam = anotherCustomParam thisauthClient = authManager async { const username = thisldapClientusername // You can use username to find user data in DB (lets imagine you are using Sequelize:) const userData = await UserModel-> const token = super const roles = userDataroles return username description: userDatadescription token roles }}
Now you can use it as follow:
const ldapAuthManager = url: 'ldap://127.0.0.1:389' baseDn: 'dc=my-company,dc=com' idKey: 'cn' const MyOwnUserProviderCnf = anotherCustomParam: 'Whatever you need' jwtPrivateKey: 'XXXXXXXX' jwtExpiration: 60 * 60 thisldap = manager: ldapAuthManager provider: MyOwnUserProvider providerOptions: MyOwnUserProviderCnf