-
Notifications
You must be signed in to change notification settings - Fork 4
Overriding the default authentication scheme
###Overriding the Default Authentication Scheme
Likely the first thing you're going to want to do after installing the komainu security microframework is configure it to perform authentication specific to your application. Using test credentials will only get you so far. Authentication with Komainu comes in two forms;
- User / Login Authentication
- Resource Authentication
We'll cover both in this documentation.
Before we get into the details of how to customize this aspect, it's important to understand the default event chain in regards to the login process. The following events will be fired consecutively when the framework detects a loginRequest
;
loginRequest
login
If login
was successful;
loginSuccess
initSession
sessionStarted
If login
was unsuccessful;
loginFailure
loginShow
In order to implement your own means to authentication a login request is to override the default login
event listener. As specified in the API documentation this listener expects the following arguments (in order);
-
req
: Object representing the current request. -
res
: Object representing future response. -
username
: Should be self explanatory. -
password
:
So in order to properly override the default implementation, you would simply need to add your own event listener to the SecurityProvider
;
var express = require('express'),
komainu = require('komainu');
var sp = komainu.createSecurityProvider();
// here's where you implement your own custom login authentication
sp.on('login', function(req, res, username, password) {
/*
* You can now evaluate both the provided username and password
* against whatever domain user store you need in order to authenticate
* the login request.
*/
if ({login was successful}) {
// make sure to emit the next two events to complete the auth chain
sp.emit('loginSuccess', req, res, username);
sp.emit('initSession', req, res, username, password, keys);
} else {
sp.emit('loginFailure', req, res, username);
}
});
The general contract to which you'll need to adhere when providing your own login
event listener is that within the callback provided to the listener you must emit the following events under the following conditions;
A successful login attempt must emit;
loginSuccess
initSession
A login failure must emit;
loginFailure
The keys
parameter that the default event listener for initSession
can be any object or collection of objects that suits your domain security needs. The default initSession
key is nothing more than a simple string with a value of LOGGED_IN_USER
but don't think that this restricts your domain security model, it doesn't. Whether you require Roles, Permissions or some other more specific data element, you can represent those in keys
, simply pass it along in the initSession
emission. The default event listener for initSession
will take that value and set it in a user-specific session like so;
req.session.security = {
keys: keys
}
So as long as that session remains valid, you can access the keys in req.session.security
. As a side note, the session
itself is initialized and maintained via the express.session()
or connect.session()
middleware instances which must precede the sp.secure()
one.
Now that you've got custom keys in the session, you must lastly ensure resource authentication takes them into account when authentication a request.
This is where the sp.secure()
method comes into play. The secure()
method of the SecurityProvider
will return a connect-friendly closure that will consult with the session structure to determine whether or not access should be given to any requested resource. This closure maintains a reference to a default authenticator
. An authenticator
is a function whose method signature is function(req, res)
- it's as simple as that. It is the responsibility of the authenticator to return a boolean value indicating whether or not access should be given, taking into consideration req
and/or res
information. Seeing as how session
information may be available in a req
that the authenticator processes, it is easy to evaluate session keys to derive an access result. Providing your own authenticator to do just that is as simple as passing it into the secure()
method when it is invoked;
var express = require('express'),
komainu = require('komainu');
var app = module.exports = express.createServer();
var sp = komainu.createSecurityProvider();
app.configure(function() {
app.use(express.cookieParser());
app.use(express.session({secret:'mysecretkey'});
app.use(sp.secure(function(req, res) {
/*
* Provide your custom authenticator here.
* Make sure to return a boolean `true` or `false`
* and consult `req.session` to check for the existence
* of and values for `req.session.security.keys`.
*/
}));
});
The above authenticator
will be globally applied to all requests (as long as one is not being ignored) because it was provided in app.use()
. However you will most likely need to apply different "rules" to different routes. Remember that the secure()
method of the SecurityProvider
instance will return a closure which maintains a reference to the supplied authenticator
, so this can easily be accomplished by provided a route-specific authenticator
implementation as middleware for individual routes;
app.get('/', sp.secure(function(req, res) {
/*
* The authentication logic provided in this route-specific
* `authenticator` is, you guessed it, only applicable
* to requests that will be mapped to the below route.
*
* Don't forget to consult with `req.session` to determine
* whether or not the active session should have access and
* return a true or false.
*/
}), function(req, res) {
res.render('index', {
title: 'Express'
});
});