Handling custom external authentication

You can use global events to integrate external user databases, and modify the authentication or authorization process. See the SecurityEvents section of the global event reference to learn more about the available options.

To set up custom authentication, implement a handler for the SecurityEvents.Authentication.Execute event. You can access the authentication data through the event handler’s AuthenticationEventArgs parameter, which provides the following properties:

  • UserInfo User - an object representing the user attempting to log in. The object is the result of the system’s standard authentication check. If the default authentication failed, the User property is null.
  • string UserName - contains the username entered during the login attempt.
  • string Password - contains the password entered during the login attempt.

Once you complete the external authentication process in the handler’s code, assign a matching UserInfo object to the AuthenticationEventArgs parameter’s User property. If the authentication failed, set the property to null.

Example

The following example demonstrates how to integrate external user authentication by handling security events:

  1. Assign a handler to the SecurityEvents.Authentication.Execute event. The example uses a custom class in the App_Code folder:

    
    
    
     using System.Data;
    
     using CMS.Base;
     using CMS.Membership;
     using CMS.DataEngine;
    
     [AuthenticationHandler]
     public partial class CMSModuleLoader
     {
         /// <summary>
         /// Custom attribute class.
         /// </summary>
         private class AuthenticationHandler : CMSLoaderAttribute
         {
             /// <summary>
             /// Called automatically when the application starts
             /// </summary>
             public override void Init()
             {
                 // Assigns a handler to the SecurityEvents.Authenticate.Execute event
                 // This event occurs when users attempt to log in on the website
                 SecurityEvents.Authenticate.Execute += OnAuthentication;
             }
         }
     }
    
    
     
  2. Define the handler method (inside the custom CMSLoaderAttribute class):

    
    
    
     private void OnAuthentication(object sender, AuthenticationEventArgs e)
     {
         // Checks if the user was authenticated by the default system. Only continues if authentication failed.
         if (e.User == null)
         {
             // Object representing the external user
             UserInfo externalUser = null;
    
             // Gets the credentials entered during the authentication
             string username = SqlHelper.GetSafeQueryString(e.UserName);
             string password = SqlHelper.GetSafeQueryString(e.Password);
    
             // Path to an XML database file
             string xmlPath = HttpContext.Current.Server.MapPath("~/userdatabase.xml");
    
             // Reads data from the external database
             DataSet userData = new DataSet();
             userData.ReadXml(xmlPath);
    
             // Authenticates against the external database
             DataRow[] rows = userData.Tables[0].Select("UserName = '" + username + "' AND Password='" + password + "'");                
             if (rows.Count() > 0)        
             {
                 // Creates a user record if external authentication is successful
                 externalUser = new UserInfo()
                 {
                     IsExternal = true,
                     UserName = e.UserName,
                     FullName = "ExternalUser Fullname",
                     Enabled = true
                 };
             }
    
             // Passes the object representing the user (or null if external authentication failed)
             e.User = externalUser;
         }
     }
    
    
     
  3. Save the class.

The system now performs authentication according to user data from the external source if default authentication fails.

We recommend importing all external roles into the CMS_Role table of the Kentico database. You can then configure the appropriate permissions for these roles, and fully use the built-in security model together with external users.

If you need to implement custom security logic, create handlers for the available SecurityEvents. You can programmatically check if a user belongs to a role by calling the IsInRole(string roleName, string siteName) method for UserInfo objects.