GROUP MANAGEMENT AND PLUGABLE AUTHENTICATION

Introduction

When managing hundreds of projects and users, as we are doing in our company, we soon need a lot of time for the management of Mantis. There are a lot of users who need different rights on different projects depending on the team they belong to. Teams and projects are not always linked together.

In our company, for example, we have what we call “solutions”, each of them is composed of a set of projects. One project can be used by several solutions. There are solution-qualification teams which members should be able to report on all solution projects. Adding a member to such a team requires that each manager of each concerned project add reporter rights to this new member.

A time-saving solution would be to create the notion of user groups in Mantis. While these user groups may be managed by an external identity provider (like LDAP for example), it would be easier to work to this issue just after working in the plugable management issue (see http://www.mantisbt.org/wiki/doku.php?id=mantisbt:issue:4235 for more information about this subject).

Groups

Existing

The current way for managing user rights is to use one of the pre-defined access levels. These levels can be customized using the “config_inc.php” file, but the concept of “levels” does not always match the user needs. Indeed, we may need that a category of users can execute a command A but not B, whereas another category can execute B but not A. We cannot say then that one category has a higher level than the other.

Principle

A new object type named “group” is created and access levels are removed. A non-removable group named “ADMINISTRATOR” is created for all Mantis administrators.

A new object type named “account” is created and contains all users and groups.

A group contains a name and links to users and groups who are members of the group. All permissions given to the current group are also recursively given to its members.

If groups are managed by Mantis (not by external identity provider), a group also contains a list of users and groups who are group managers. They represent users who can manage the members of this group and rename the group. One value of this list can be “[self]” and would mean that every member of this list is also manager (this is the case for the “ADMINISTRATOR” group).

At every point of the product where we need to grant rights to anyone, and for each specific type of right, we should find a list in which accounts can be added (or removed).

At some of these points, the list may contain special values like “[self]” (in the group page to indicate the members of the current group), “[author]” (to indicate the author of the issue, the note, the new, etc.), “[assignee]” (to indicate the person to which the issue is assigned), “[nobody]” or “[everybody]”.

It is still possible to create a hierarchy of groups by including groups of higher privilege in the groups of lower privilege.

Administrators

People of the “ADMINISTRATOR” group have special privileges:

  • They can create or remove groups, if groups are managed by Mantis.
  • An administrator can also put himself in any group and then can take all rights to do any action, if groups are managed by Mantis.
  • Administrators can access a special page (“manage rights”) used to set rights on different actions.

The “manage rights” page defines which people or groups can do what actions. The actions we would find there can be: create, modify or remove news, users, custom fields or profiles, change configuration, create, delete or modify each field of projects and everything which currently defines an access level in the config_inc.php file.

Concerning projects, this page should also allow setting default values for every action linked to the project, like manage project level news, versions, categories, used custom fields, view, create, modify, correct (be assigned to), delete an issue, and every available status of issues. It should also be possible to set notifications the same way, i.e. define which user or group will be notified when a new issue is created in the project, or when changes are done to issues.

Migration

While migrating from an older version of Mantis, a few changes need to be done:

  • In the “constant_inc.php” file, access level constants are replaced with strings of the same name (e.g. define( ‘VIEWER’, ‘VIEWER’ );).
  • In the “config_defaults_inc.php” file, remove the “access_levels_enum_string” variable.
  • Create a group for each access level, containing all users with this level and every group created for higher access level :
    • Create the “ADMINISTRATOR” group and put all administrators in it.
    • Create the “MANAGERS” group and put all managers and “ADMINISTRATOR” group in it.
    • And so on…
  • Change database to remove access level for the users.
  • Create a table with more precise access rights for project, fill in this table using the currently set access rights and remove the current access rights.

Management

New pages should be created for the group management. They will be used for the Mantis default authentication plugin. These pages could look like the pages for user management. We should have one page with the list of all groups, and one page with the details for a given group.

This last page could be used to change the group name, set the managers of the group (set to “[self]” and not editable in the “ADMINISTRATOR” group), and set members of the group. All these elements are only editable by group managers and administrators.

For this same default plugin, before the “Add user to project” box, the “manage_user_edit_page” must contain a “Add user to group” box, built the same way, which allow to set the user as member of groups.

Projects

When created, projects are defined with the default values set in the “manage rights” page. They, of course, can be modified. Managing access to a given project may seem more complex because of all possible options instead of current access levels. But actually, if groups are well used, these accesses should be done once when creating the project. Managing access should only be done by managing group members.

Detailed specifications

These specifications are for both the group management and the plugable authentication.

Database

Create mantis_account_table (for both users and groups):

  • id (primary key)
  • type (0 for user, 1 for group)
  • company_id (the identifier used by the login plugin, this could be the username or something specific to the company - login plugins should care not to have similar ids)
  • date_created
  • enabled

Change mantis_user_table:

  • id (primary key, foreign key to mantis_account_table)
  • last_visit
  • login_count
  • cookie_string

Create mantis_plugin_Login_user_table (if default login plugin is used):

  • id (primary key, copied to the corresponding company_id in mantis_account_table)
  • username
  • realname
  • email
  • password
  • lost_password_request_count
  • failed_login_count

Create mantis_plugin_Login_group_table (if default login plugin is used):

  • id (primary key, copied to the corresponding company_id in mantis_account_table)
  • groupname

Create mantis_plugin_Login_group_members_table (if default login plugin is used):

  • group_id (primary key, foreign key to mantis_plugin_Login_group_table)
  • account_id (primary key, foreign key to mantis_account_table)

Create mantis_plugin_Login_group_managers_table (if default login plugin is used):

  • group_id (primary key, foreign key to mantis_plugin_Login_group_table)
  • account_id (primary key, foreign key to mantis_account_table)

Create mantis_access_table (containing strings corresponding to different access)

  • id (primary key)
  • name (access name, for example create_news would represent the access needed to create news)

Create mantis_access_user_table

  • access_id (primary key, foreign key to mantis_access_table)
  • account_id (primary key, foreign key to mantis_account_table)

During a migration, default login plugin is automatically installed. User data are split into all different tables. The mantis_access_table is filled with the different available access strings. The mantis_plugin_Login_group_table is created with default groups. Connections are created between groups, users and access strings.

Access API

A new graphical element is created to manage accesses. This element is composed of a double-list with all available groups and users (must be able to filter) in the first list and all the selected groups and user in the other list. In each case, we can add or remove groups or users which should have access to the action. This element is used in every part of the software where we should be able to set up authorisations.

In the database, each action requiring authorisation is represented by a string (in mantis_access_table). This access is linked to accounts (using the mantis_access_user_table) which have the associated permission.

The access API is modified to manage the new access system. Instead of quering for levels, one should only test if the access (using the representation string) is allowed to a given user.

Login plugin

Two virtual classes are created, one for managing user data (User.class.php) and one for managing group data (Group.class.php). These classes must be overloaded by the login plugins.

A new class is created for the login plugins. Login plugins should simply extend the MantisLogin.class.php which itself extends the MantisPlugin.class.php. This class handles the newly created events:

  • EVENT_LOGIN_AUTHENTICATE (EVENT_TYPE_FIRST): Plugins try to authenticate the user. Returns null if user cannot be authenticated or the instance of the User.class otherwise.
  • EVENT_LOGIN_AUTHENTICATE_BY_NAME (EVENT_TYPE_FIRST): Plugins try to authenticate the user using a given username and optionally a password. Used for script login. Returns null if user cannot be authenticated or the instance of the User.class otherwise.
  • EVENT_LOGIN_NEED_FORM (EVENT_TYPE_DEFAULT): Each plugin indicates if it needs to ask information to user for authentication.
  • EVENT_LOGIN_FIELDS (EVENT_TYPE_OUTPUT): Mantis is about to ask username/password to the user. Plugins can ask for additionnal information.
  • EVENT_LOGIN_EXTRA (EVENT_TYPE_OUTPUT): Mantis is about to ask username/password to the user. Plugins can add “signup”, “forgot password” or other kinds of links.
  • EVENT_LOGIN_GET_USER (EVENT_TYPE_FIRST): The parameter is the company_id of the user, given as a string. Each plugin must look if it can return a matching User.class corresponding. Returns null otherwise.
  • EVENT_LOGIN_GET_GROUP (EVENT_TYPE_FIRST): Same than EVENT_LOGIN_GET_USER, but for groups.
  • EVENT_LOGIN_SEARCH_USERS (EVENT_TYPE_DEFAULT): Search for users having either username, real name, name or first name (depending on the data provided by the plugin) matching the input. If the input string is smaller than a given number of character, searches for exact match. Otherwise, search for users containing the given string. Each plugin returns an array of User.class.
  • EVENT_LOGIN_SEARCH_GROUPS (EVENT_TYPE_DEFAULT): Same than EVENT_LOGIN_SEARCH_USERS, but for groups. The search is made in group names (depending on the data provided by the plugin).
  • EVENT_LOGIN_LOGOUT (EVENT_TYPE_EXECUTE): The input is the User.class of the current user. If plugin managing the given user can handle it, tries to logout the user.
  • EVENT_LOGIN_LOST_PWD (EVENT_TYPE_FIRST): Sent when user forgot his password. Parameter is the internal username used by plugin. First plugin knowing the given user handle the message and returns true, othe plugins return null.

The login procedure is the following:

  • First of all, the EVENT_LOGIN_AUTHENTICATE event is sent.
  • The first plugin authenticating the user returns the User.class instance.
  • If the event result is null (no plugin could authenticate the user), send event EVENT_LOGIN_NEED_INFO.
  • If at least one of the plugin answers true, display a login page (sending an EVENT_LOGIN_INFO event) which will call this procedure again.
  • If the login procedure already has username or password information (meaning it already is the second chance, with info provided), then a null result throws an error and stops login procedure.
  • When the user is authenticated, check that the company_id already exists in the Mantis tables. Create the user if not.

The User.class contains methods to get information about a user:

  • getName() → returns the real name of the user.
  • getEMail() → returns the e-mail addresse of the user.
  • getAvatar() → returns the avatar for the user.
  • isEnabled() → indicates if the user is enabled.
  • update() → returns an URL to use to update the user data or null if not modifiable.

The Group.class contains methods to get information about a group:

  • getName() → returns the group name.
  • getMembers() → returns the User.class and Group.class which are members of this group.
  • getOwners() → returns the Group.class of groups which owns this group.
  • getAllMembers() → returns the User.class which recursively are members of this group.
  • getAllOwners() → returns the Group.class of groups which recursively owns this group.
  • update() → returns an URL to use to update the group data or null if not modifiable.

Standard login plugins

A few standard login plugins will be created to replace at least the already existing connexion types.

Default

The default plugin (named Login) replaces all “internal” storage. This plugin should have 2 parameters:

  • The identifier prefix (to avoid conflicting with another plugin).
  • The type (MD5, PLAIN, CRYPT, CRYPT_FULL_SALT). Default type is MD5, other are deprecated.

The plugin must provide pages to modify user or group data, with access control on all fields (everyone cannot modify any field). It should define extra database tables: mantis_plugin_Login_user_table, mantis_plugin_Login_group_table, mantis_plugin_Login_group_members_table.

Others

Some other plugins (BasicLogin, HttpLogin and LdapLogin) should hold the code currently existing in Mantis core (authentication_api.php). It would allow user to use one of the already existing other login solution.

Another plugin (RemoteLogin) using the REMOTE_IDENT variable (RFC 931)could also be created.

Important

Login plugins will need to care of some traps:

  • As groups may be included in some other groups, there may be (depending on the plugin policy) cyclic references. When in recursive procedures, plugins should avoid infinite loops!
  • Each plugin should take care of using a different company_id range. Typically, there will be the real id used by the company LDAP, and maybe the ids for other users, used by the default plugin. The latter should then allow administrators to use something like a prefix for the id to always be different from the first one.
 
Logged in as: anonymous
mantisbt/issue/3444.txt · Last modified: 2010/03/05 05:05 by sveyret