The human side of software development.
Applying development practices against every-day life, and applying life lessons to development
This is developer++
Recently at my day job, we had a requirement to build a stand-alone application that integrated with other various systems already in production.
This resulted in an LDAP authentication web service returning JSON web tokens with Rabbit MQ integration with other services. Source code on Github
Because there are already a number of different authentication systems in place, we did not want to introduce another set of credentials, and the core system required running legacy code on the backend to authenticate rather than just a database or web service hit, so we settled on writing a new web service authenticating through the Windows network (LDAP).
We have been heavily experimenting with Node.js for this project, as well as proving a concept for a highly modularized architecture.
The main goals are to allow highly focused services to run independently of each other, written in whatever language / toolset best suits the task, and having them all speak to each other through the Rabbit MQ server.
Here is an overview of the architecture in place for a single application. The green boxes are applications / services specific to a defined task. The blue boxes are shared services that will be used by many sub-systems as the infrastructure grows.
The system consists of 4 different parts:
- AngularJS front end – served by Node Backend API
- Node app using express and connecting to a Postgres database and a legacy DB2 database
- LDAP service – Node application that is binding to the LDAP server, authenticating a login attempt, and returning a JSON web token (JWT)
- Rabbit MQ server – handling all communication between services
There are 7 steps from logging in to receiving data:
- AngularJS posts a Login attempt – this is a standard form POST containing a username and password.
- The LDAP service authenticates the username and password against the Windows LDAP server and returns a JSON web token.
- AngularJS is now authenticated and requests data from Backend API. The token is included in the headers of the request. All future requests from AngularJS have the token in the headers.
- When the Backend API receives a request for data, it passes an RPC message to the Rabbit MQ server containing the token, asking for validation of the token.
- The LDAP service receives the message from Rabbit MQ and validates the token by decoding it (it’s not another hit to the LDAP server). A success code and user information is returned to the Rabbit MQ server.
- The Rabbit MQ server completes the RPC request and relays the validated token result and user information to the Backend API.
- The Backend API then queries the database(s) and returns the requested information to AngularJS for display.
After the front end has authenticated, future requests skip steps 1 and 2 above.
This may seem overly complex for this simple use case, but I’m expecting this system to grow substantially over time, and by setting up a flexible architecture early on, we can be better prepared to incorporate new and / or existing systems into the infrastructure as easily as possible.
RPC Call Example
The LDAP service is listening for RPC calls through Rabbit MQ:
On the backend API using Express, I protected specific API endpoints by implementing an authentication mechanism as part of the route definition as follows:
This is the contents of jwtauth.js that actually finds the token and sends it through Rabbit MQ for validation from the LDAP service:
Potential Improvements / Upgrades
A possible upgrade suggested by Ted Kulp is to implement a Redis cache of all tokens at the Backend API to limit the number of hits to the LDAP service The LDAP Service would write all granted tokens to the Redis cache. This would allow the backend API to check the cache for a valid token directly rather than going through the RPC call.
The LDAP service has no sense of roles or authorization. This should be handled by the calling service.
The LDAP service is passing back the list of groups that the user belongs to, so it is quite easy to handle authorization based on the AD groups the user belongs too. This is often already setup for file access and other applications, so it’s something to taken advantage of if your organization operates this way.
Thanks for visiting!
If you enjoyed this article, please subscribe to my newsletter below and I'll make sure you are notified of any future articles
As a thank you for signing up, you will receive my free ebook - Iterative Development for the Human Condition. This book takes a look at how the same principles used in software development can be used to effect positive changes at a personal level.[nm-mc-form fid="1"]