Custom
This page provides some guidance on how to define your own custom Authentication Adapter class for use within the Application Server.
Note: If you're looking information on how to easily integrate a third-party Authentication Provider into the Application Server, we recommend first taking a look at the Default Adapter as it can be configured to work with many third-party SSO solutions pretty easily.
Implementation Class
We recommend extending the AbstractAdapter class. The basic skeleton of the class might look like this:
var AbstractAdapter = require("cloudcms-server/middleware/authentication/adapters/abstract");
class CustomAdapter extends AbstractAdapter {
constructor(req, config) {
super(req, config);
}
identify(req, callback) {
super.identify(req, callback);
}
}
module.exports = CustomProvider;
In your app.js
file, you can then register this custom adapter like this:
server.init(function(app, callback) {
auth.registerAdapter("customAdapter", require("./customAdapter"));
callback();
});
And you can then register it via config:
server.start({
"auth": {
...,
"adapters": {
"myAdapter": {
"type": "customAdapter"
}
}
}
});
Implementation Details
Here are some notes to aid in your implementation.
constructor
In this section, you will generally want to initialize any configuration options ahead of calling into the super method. The config that was provided in the server.start()
call for the adapter is available in the config
variable.
For example, you might do this:
constructor(req, config) {
if (typeof(config.strict) === "undefined") {
config.strict = true;
}
super(req, config);
}
Where strict
is completely contrived example of setting a default. You could later access this setting to, say, adjust how the identify
method works. See below.
The config
is a member variable and can be accessed from the other methods, allowing everything to be configuration driven. The other methods can simply reference this.config
to get at configuration settings.
identify
This method interrogates the incoming request and extracts essential properties that can be used to identify the user.
The assumption here should be that the incoming request is -not- trusted. It isn't guaranteed to be telling the truth and could be spoofing information. Our job here is to extract what information we can and then determine whether that information should be considered as trusted by rest of the framework.
If nothing can be extracted from the request, then the callback should hand back undefined
or null
.
Otherwise, it should hand back properties
object.
If a properties object is handed back, we know that the request had some identifying information. At a minimum, the properties handed back should consist of:
{
"token": <identifier>,
"trusted": <boolean>
}
Where:
token
is the primary identifier (unencrypted or unencoded)trusted
indicates whether the properties being handed back can be trusted
If the properties are marked as trusted, this means that that properties being handed back were extracted from the contents of the token in such a way that we know they can be trusted. The authentication framework can regard these properties as valid. This is usually only possible if the token is encrypted and sent over HTTPS so that no man-in-the-middle attack is possible. It applies to certain token types, such as encrypted JWT.
If the token
is trusted, then the load
method on the Authentication Provider can be used to simply load the user's profile and proceed. Otherwise, a verify
call must first be made to verify that the token
is valid and real.
In addition, if the token
is trusted, it may be extracted from and this method may hand back a profile
and a user_identifier
. This is useful for purely stateless situations where the token is trusted and contains an encrypted assertion of the user identity (i.e. the profile
). In this situation, the profile will also be trusted and there is no need to verify or load the profile using the Authentication Provider.
In that case, the properties
object may come back like this:
{
"token": <identifier>,
"trusted": <boolean>,
"profile": {
"unique_name": "jsmith",
"given_name": "Joe",
"family_name": "Smith",
"email": "jsmith@company.com"
},
"user_identifier": "jsmith"
}