The introduction post sort of served as a primer about why I wanted to create this module. This post is going to talk about technical side of the module and for what it should (and shouldn’t) be used. Or something like that. We’ll see where it went once I’m done writing it.
Every site that wants to deliver customized content needs a way to recognize the user. The more customized and personal, the more likely you’ll want actual user identification rather than just plain browser recognition.
I figured that most sites I want to build will have some element of user identification, I may as well write a module that I can drop in and get going without having to worry too much about recreating it from scratch each time. Thus here we are, a Java servlet based module that will allow the developer to drop in a few servlets, modify a configuration file or two, and have a bare bones site that handles user logins from a variety of 3rd party systems.
Yeah, it’s what I like, and what I still think is pretty relevant when it comes to server side content. I debated if I wanted to try something new, but I think for the backend, I’m comfortable with Java and it provides well in terms of support and being able to find and use libraries. I’ll save my experimenting for front end work.
I also want to have this divorced from any particular system or infrastructure so that it can just run. No need for anything WebSphere or Tomcat or Glassfish specific or any deep configuration of LDAP or JAAS or some security module. Just alter a property file and you’re good to go. Now, is this the right way to do it? Well, that can be debatable especially since these servlet systems do offer a lot of robust options, but I also just want to give creating this project a shot.
In the end, it’s meant to serve needs that I’m identifying during site creation, so that’s my driving force. Along the way, I hope that it may be of help to others who want a bootstrap base to explore and jump from. We’ll see how well that gets accomplished.
The basic idea is to:
- Have a screen with a bunch of login buttons.
- Upon user click, initiate the needed redirection and prompting defined by the flow requirements of the 3rd party systems.
- Upon proper authorization, grab the basic data returned from the 3rd party and present that information to the backend system to allow it to use it for a customized user experience.
A collection of 4 servlets, 2 of which are more core, and the other 2 slightly more optional (read: yet to be fully implemented).
- LoginServlet - Triggers sending the browser to the official authentication page of the 3rd party system.
- CallbackServlet - Location the browser will be sent to after the user has authenticated with the 3rd party. This is usually a registered address with the 3rd party system or passed to it as part of the initial login (automatic).
- LogoutServlet - A way to remove the current user information from the browser session.
- DisconnectServlet - A way to decouple the 3rd party system from the user. ie. Remove authorization to leverage that 3rd party platform.
Looking aside the last 2 for now (since their implementations are on the lesser scope of interest), the system really only requires 2 solid servlets to function.
com.subdigit.auth.servlet.LoginServlet instantiates the
com.subdigit.auth.AuthenticationHelper class which is what actually handles the gritty details. I did this with the hope that I can easily decouple the system from a specific servlet framework instance. For now the AuthenticationHelper requires the servlet’s request and response to be passed in so that it has access to the necessary information, but I can see this evolving so that you can extract the information from any source into the AuthenticationHelper to have it behave accordingly with 0 requirement to be in a servlet environment at all.
The AuthenticationHelper is issued a
authenticationHelper.connect() call to start the process. It figures out which 3rd party system you’re calling, finds the proper class that can handle that system’s requirements (which needs to extend the
com.subdigit.auth.AuthentcationService interface), dynamically loads it, and calls that service’s
authenticationService.connect() method. That method creates the URL to the 3rd party system with all the required parameters (like the application id and key) and redirects the browser to it to prompt the user to authenticate.
Once the user authenticates, the 3rd party system is told to callback to the
com.subdigit.auth.servlet.CallbackServlet which instantiates another AuthenticationHelper that chains the same AuthenticationService to call the
authenticationService.validate() method. At this point, the system usually has an abstract token for the user, which then needs to be looked up with the 3rd party system to get the relevant details (like name, email, etc). Each service varies how this is done, which is why we need a per-service class (See the
com.subdigit.auth.service package) that can handle these issues per 3rd party you want to connect to the Authentication Module.
Once the user’s information is retrieved, the service then packages all the data it has into an
com.subdigit.auth.AuthenticationResults object which is floated back up to the CallbackSservlet. At the CallbackServlet level, the developer can probe the AuthenticationResults object’s various methods to access the stored information about the user. This will then allow the developer to correlate the data in the AuthenticationResults object to an existing user in the local datastore or to create a new user.
Download the source from GitHub:
github clone https://github.com/subdigit/authentication.git
That should get you an
authentication/ directory. You will need to copy:
src/main/resources/authenticationserviceconfiguration.properties.sample -> src/main/resources/authenticationserviceconfiguration.properties
And fill in the appropriate
.appsecret values for the services you want to use. It’s a hassle, but you’ll need to figure out the developer pages for the services and do the whole registration of your app there. Some URL hints for that are on the project’s README.md file. Once inserted, make sure the
.enabled is set to true for the ones you will use.
To run a test instance, be sure you have Maven installed and run:
That should fire up a bare bones system on localhost:8080. The systems you’ve enabled should show up there and you should be able to click and log into the test page with them. Should :).
The servlets provided are really bare bone samples. Take the flow in each of the goGet/doPost of the servlets and implement your own desired customizations in them. You can probably copy the LoginServlet as is and write your own LogoutServlet for however you want to get the user logged out. The only one where you should modify the code would be in the CallbackServlet. Once the AuthenticationResults object is returned from the
authenticationHelper.validate(), this would be where you need to probe the results to figure out who the user is and how they relate to your existing system (new user, existing user, etc). At this point you will need to decide where to redirect the user to and if a new account needs to be created and so on.
authenticationResults.getServiceUserID() will return back the primary user identifier from the 3rd party system and
authenticationResults.getService() will let you know the 3rd party service in question. That should be enough information to find that same user in your back end and load their information. If they are new, you can get back some information from
authenticationResults.getVariable(<String>) or get back all the parsed data via
HashMap<String,Object> authenticationResults.getDataStore(). And if you still need more information, you can get the actual object that was returned back from
Object authenticationResults.getReturnData(). You will need to look into the code for each service to find out what type of object is being stored.
If you have any questions about how to get this working, feel free to leave them here or to just bug me on Google+. Twitter is ok too, but the 140 character limit will just end up being frustrating.
Oh, and be more than free to do what you want with the code, just that if you make any changes, share them!
yeah, it’s still got a while to go, but this can be a start.