Custom Authentication

If you already have a user management system (ie: LDAP) that you wish to use instead of Mango's built in author logins, you can provide a custom ColdFusion component that will handle the login for Mango to use. Furthermore, you can use your own system and Mango's both at the same time, in the order you specify.

To do so, you must create a ColdFusion component that must contain these two functions: init and checkCredentials.

<cffunction name="init" access="public" output="false" returntype="any">
   <cfargument name="mainApp" required="true" type="any">
   <cfargument name="settings" required="true" type="struct">
   
   <cfreturn this />

</cffunction>

<cffunction name="checkCredentials" access="public" hint="This should return a credential object">
   <cfargument name="credentials" type="any" required="true" hint="This should be a model.Credential object" />
   
   <cfreturn arguments.credentials />

</cffunction>

Your component will be instantiated every time there is a user attempting to login. Mango will first call the init function and the the checkCredentials function.

Once you have created your component, you need to modify your configuration file so that Mango will know to delegate the login to your component.

Configuring your custom authentication system

In every configuration file (config.cfm), there is a node called "authorization". Within that node, there is a key called "methods". In order to start using your component, you must change the methods from the default "native" to "delegated". Then in the settings node within authorization, you'll need to specify the name of your component. You can place your component anywhere you want, but the name of your component must include either the path from the root of your site to the component (ie: myBlog.myComponent), or a mapping used to find the location of your component (myMapping.myFolder.myComponent).

At a minimum, the node will look like:

<node name="authorization">
   <map>
      <entry key="methods" value="delegated"/>
   </map>
   <node name="settings">
      <map>
         <entry key="component" value="mycomponents.AuthorizerTest"/>
      </map>
   </node>
</node>

In the example above, I created a delegate component called "AuthorizerTest", which is placed in a folder called mycomponents, off my website root.

In the 'methods' key, you can have 'delegated' or 'native', or any combination of the two. If you specify both, for example: "native,delegated", then Mango will try to login the user using its native database, but if not found, it will call your component. If you have them in the opposite order, then your component will be called first, and if your component does not find the user, then Mango will attempt to login the user using its native database.

Custom settings

Your component may need some settings in order to accomplish its job. You can use the settings node to add any custom settings, and they will be sent to your component, in a structure, as the second argument of the init function.

You add those settings at the same level as the 'component' settings, for example:

<node name="authorization">
   <map>
      <entry key="methods" value="delegated"/>
   </map>
   <node name="settings">
      <map>
         <entry key="component" value="mycomponents.AuthorizerTest"/>
         <entry key="YOUR_PROPERTY_NAME" value="YOUR_VALUE"/>
      </map>
   </node>
</node>

In the example above, you will be able to access YOUR_PROPERTY_NAME value from the init() function:

arguments.settings.YOUR_PROPERTY_NAME

You can have as many of these settings as you need.

Validating user credentials

When a user tries to login, Mango will call the checkCredentials method. This method has a single argument, of type Credential (you can find it in folder component/model/Credential). At this moment, the credential object only contains the username and password provided by the user from the login form. You should use those to determine whether the user is allowed into the administration or not. Once you determine that, you will need to provide additional information about this user, particularly the permissions or role this user has.

Once you have provided the information, you will need to return the credentials back to the caller.

The Credential object has the following properties:

isAuthorized (required)

Mango determines whether or not the user should be let in by looking at the property "isAuthorized" in the credentials object you return. You must set it to true if you want the user to enter into the admin. If false, the user will see an "Invalid login" message.

username (required)

The credentials object you receive already contains a username. If you send the same credentials object back to the caller, then you don't need to do anything. This username must be unique within all Mango users, including those already existing in Mango's database. You can change it before sending the object back if you need to.

password

The credentials object you receive already contains the password. This password will be set in Mango's database (all passwords are salted and hashed). If you prefer not to store the password, then you must set it to empty string before sending the object back to the caller. If set to empty, Mango will generate a random password, just so that the user in the database is not stored without a password. Since nobody is notified of the password and the passwords are hashed, this will "lock" the user out if you stop using your own authentication method, until an administrator changes the password to a known one. If you don't clear it, and the real password is stored, then after you stop using your custom authentication method, the user will be able to enter into the admin using his password.

name

This is the name of the author. If you don't provide it, then the username will be used as name. It is recommended to set it to a nicer name. If the username is john.doe, you may want to set the name property to "John Doe". Usually, this name is displayed as the post author in the blog.

email

User's email. It's not required, but if not passed, user will not be able to receive email notifications, and comments will not show as author comments. Strongly recommended.

permissions

A list of permissions for this user. You must provide this or a roleId. If both permissions and roleId are empty, the user will be able to login, but he/she will have no permissions to do anything. For a list of permissions, refer to the table "permissions". Example: "manage_posts,manage_pages".

roleId

This is the role the user will have while logged in. It will determine its permissions. If you provide a roleId, it will take precedence over the permissions list and the permissions property you set will be ignored.

This id is the id defined in your Mango install database. You should use it only if you know the ids and you are sure those won't change (roles cannot be deleted from the administration, but their ids can change if their names change).

You can use the RoleManager to get the role id based on a list of permissions. Although passing the permissions list or passing an id that has the same permissions will be equivalent, the main difference is that if you don't specify the roleId, Mango will create an extra role for those users. If you don't want that, then it is preferable to use RoleManager.getRoleByPermissions(permission_list) to get the roleId based on your permissions list. If no role is found that matches those permissions, an exception will be thrown. You can use the mainApp variable passed to your component in the init function to get to the RoleManager (mainApp.getRolesManager()).

If you want the administrator to be able to set roles from Mango's administration, you'll have to ask Mango for the user's current role before setting it. In this way, you'll always have the latest role information, in case the administrator has changed it from the administration. To do that, you'll need to access the AuthorManager (mainApp.getAuthorsManager()). Then use the function getAuthorByUsername(username) to get the author information.

Tips

When you install Mango, you must enter an administrator username and password. If you know that you will be using your own authentication method, it is recommended to set the username of this administrator to a known username in your own authentication method. If you do so, once you set up your custom authentication system, and you login using that username, no new user will be created, and any post that you created will still be yours.

Once you have made changes to the config file, make sure to go to the Cache section of the admin and click "Reload Configuration".

You can download this example component to get you started: AuthorizerTest.cfc (rename to AuthorizerTest.cfc)