Skip to content

Sessions, authentication, user and permission systems

Filip Hnízdo edited this page Mar 14, 2016 · 5 revisions

The authPass object

Access to Iris is managed through a system of userids and access tokens which, if successfully paired together, form an authPass which contains information about a user or machine accessing the system. If userid and access tokens are not provided an anonymous authpass is created. Anonymous sessions are given an authPass with a unique userid of the format anon_<id>, e.g. anon_a3ec5e9ab42e4d1f1f09d23. This can be used to track and interact with a specific anonymous user.

An authPass typically looks something like this:

{
  roles:["authenticated", "admin"],
  userid: '1'
}

Getting a session's authPass from the Express HTTP request object.

An authPass is assigned (via token/userid checks from cookies or information provided via REST parameters) automatically as soon as a request enters the system. If you have the Express request object (typically called req) you should be able to find this using req.authPass.

Getting the authPass of a user that called a Hook

To find out the authPass of the session that started an Iris hook (see the hook system documentation for more information) look at the thisHook.authPass object inside the hook's callback function.

For example:

iris.modules.mymodule.registerHook("my_custom_hook", 0, function(thisHook, data){

  console.log(thisHook.authPass);

  thisHook.pass(data);

}

Getting an authPass from any logged in session

Sometimes you may need to get the authPass for a user that isn't that of the user making the current request. Using the currently active sessions list iris.modules.auth.globals.userList you can use a special getAuthPass method to extract a user id. This returns a promise as its internal call to hook_auth_authPass is asynchronous.

iris.modules.auth.globals.userList["1"].getAuthPass().then(function (authPass) {

        // Do something with authPass
        
}, function(fail){

       // Do something when authPass could not be retrieved.

});

Extending the authPass object using hook_auth_authpass

To extend the authPass object (add extra roles etc) you can use the hook_auth_authpass hook. The hook receives the HTTP request object in its thisHook.context object so you can read things like cookies or the requested url.

An example:

iris.modules.mymodule.registerHook('hook_auth_authpass', 0, function(thisHook, authPass){

  if(authpass.roles.indexOf("admin") !== -1){
   authpass.roles.push("superuser");
  }

  thisHook.pass(authPass);

})

Accessing currently active sessions

Currently active sessions are stored in iris.modules.auth.userList

Seeing the last time a user's session was active on the system.

The iris.modules.auth.userList object also contains a lastActivity property for each session. You can use this to find out when the user's last request was.

iris.modules.auth.userList["1"].lastActivity // Returns a timestamp

Managing authentication on the server side

There are a series of hooks that can be used to create, edit and delete access tokens for a userid.

Creating access tokens with hook_auth_maketoken

You can call hook_auth_maketoken with an object containing a userid to make a token for a user and create a session on the system for them. Note that the user calling this hook needs to have access to the "can make access token" permission (see section on permissions). A user with the admin role automatically gets all the permissions and will usually be the only caller of this function.

Here's an example from the api callback to make new tokens via the REST API:

iris.route.post('/auth/maketoken', function (req, res) {

  iris.hook("hook_auth_maketoken", req.authPass, {
    userid: req.body.userid
  }).then(function (success) {

    res.respond(200, success);

  }, function (fail) {

    res.send(fail);

  });

});

Deleting specific tokens using hook_auth_deletetoken

You can delete a specific token for a user by calling `hook_auth_deletetoken'. If a user has no more access tokens when one is deleted their session is closed.

An example:

iris.route.post('/auth/deletetoken', function (req, res) {

// req.authpass contains {userid: ..., token: ... }

  iris.hook("hook_auth_deletetoken", req.body, req.authPass).then(function (success) {

    res.send(success);

  }, function (fail) {

    res.send(fail);

  });

});

Clearing all of a user's access tokens using `hook_auth_clearauth'

If the hook-calling user has the can delete user access permission they can use this hook to clear all of a user's sessions. Useful on logging out.

Example

iris.app.post('/auth/clearauth', function (req, res) {

  iris.hook("hook_auth_clearauth", req.body.userid, req.authPass).then(function (success) {

    res.send(success);

  }, function (fail) {

    res.send(fail);

  });

});

Roles and permissions

The base installation comes with three roles, anonymous (given automatically to not logged in users), authenticated (users that have logged in but have no extra roles (again given automatically)) and "admin". Admin allows a user to administrate the whole system so should be given sparingly.

More roles can be added with one line of code in a custom module.

iris.modules.auth.globals.registerRole("contributor");

This instantly makes it visible and usable in the permissions user interface. How a role is assigned to a user is up to you and your module.

Some permissions have already been created such as permissions to create, delete, view and edit entities of various types. Modules can register additional permissions.

iris.modules.auth.globals.registerPermission("can make access token", "auth", "this allows a user to make access tokens for other users to access the system")

To grant or revoke a permission for a role, visit the permissions tab in the administration toolbar and select/unselect the relevat box for the role/permission. Then hit save at the bottom on of the form.

Checking permissions

To check a permission within a module use the iris.modules.auth.globals.checkPermissions function. This takes an array of permissions and an authPass to check against. It returns true or false.

if (iris.modules.auth.globals.checkPermissions(["my permission"], thisHook.authPass)) {

// This is run if the authPass has the "my permission" permission.

}

User accounts

Iris comes with a user system which allows people to log in to your website/application and see/do different things depending on their role. Behind the scenes this simply calls the maketoken functions when a user supplies credentials that match a user entities username and password.

Logging in

To log in to the administration system, visit /admin or /login and type in your access details.

Logging out

To log out, either visit /logout or hit the logout button on the administration toolbar.

The user entity

The user entity is a fieldable entity like any other, except for the password field (which is hashed and stored securely in the database), and a roles field where users can be given roles to allow various permissions.

Authentication when making REST requests from outside of Iris

Managing authentication

All API requests are authenticated using a credentials object included in the GET or POST as a JSON encoded object containing userid and token. To generate an access token:

POST /api/login with parameters:

{"username": YOURUSERNAME, "password": YOURPASSWORD}

If successful, a new auth object will be returned which will be used to validate future requests. You can also POST to auth/maketoken via the API to make tokens for any userid without requiring their username and password (if the user calling this has the relevant permissions).

// Credentials object
{ "userid": "1", "token": "a6b5cd4e8e3db2c18a7b2ee2" }

A new authtoken is generated on every valid call to /api/login and legacy tokens remain valid until hard server reset.

When using the API from external services, the 'credentials' object (see above) need to be passed at the root level in all requests. An example of editing an entity in jQuery would be:

iris.server = "http://localhost:3000";

var editedEntity = {
  eid: 5,
  title: 'Entity title',
  field_description: 'Example description'
};

var credentials = {
  userid: 1,
  token: 'ho87yoho87o8w7eyrfdfvfj9'
};

// The entity edit API endpoint expects to receive the entity object, but we also include the credentials to this object before sending.

editedEntity.credentials = credentials;

jQuery.ajax({
  type: "POST",
  url: iris.server + '/entity/edit/group/5',
  data: groupEntity,
  success: function (data, status) {
    console.log(data, status);
  },
  error: function(jqXHR, status, errorThrown) {
    console.log(jqXHR, status);
  },
  dataType: 'json'
});

Authenticating via websockets when using on an external site

If you wish to authenticate a web socket connection to use a particular Iris userid you will need to use the API to make an access token and then send a pair event with a credentials object containing this data.

For example:

iris.credentials = {
  "userid": YOURUSERID
  "token": YOURUSERTOKEN,
};

var socket = io(iris.server);

socket.on("connect", function () {

  if (iris.credentials.userid) {

    socket.emit('pair', {
      credentials: iris.credentials
    });

  } else {
    
    console.log("Anonymous connected with Iris")
    
  }

});

REST endpoints for authentication and user system

POST to /auth/clearauth

Parameters
  • userid

POST to /auth/maketoken

Parameters
  • userid

POST to /auth/deletetoken

Parameters
  • userid
  • token

POST to /login

Parameters
  • username
  • password

*Returns userid and token.

POST to /logout

Parameters
  • None. Logs out the user for the authpass of the request. User clearauth if you wish to log out other users.
Clone this wiki locally