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"
}