Writing a custom authentication userservice for Roadkill Wiki

Here’s how I did it:

Create a new class library project.

Add a reference to Roadkill.Core.dll and System.Web

Create your service as a class that implements Roadkill.Core.Security.UserServiceBase.

I found is simpler to inherit from Roadkill.Core.Security.FormsAuthUserService and override some methods, because this way lots of stuff you need to handle is already in place. Below is my code with some parts removed:

using Roadkill.Core;
using Roadkill.Core.Configuration;
using Roadkill.Core.Database;
using Roadkill.Core.Mvc.ViewModels;
using Roadkill.Core.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Security;

namespace MyCustomUserService
{
    public class MyCustomUserService : FormsAuthUserService
    {
        public MyCustomUserService(ApplicationSettings settings, IRepository repository)
            : base(settings, repository)
        {
        }

        public override bool IsReadonly
        {
            get
            {
                return true;
            }
        }

        public override bool Authenticate(string email, string password)
        {
			//The email passed from the login form is in my case the username
            var username = email;

            //Validate user against my own provider
            if (myUserProvider.ValidateUser(username, password))
            {
				//Create/update user in roadkill db on each authentication
				//Add your own handling to decide who should be admin/editor instead of just passing true
				if (!AddUser(email, username, Guid.NewGuid().ToString(), true, true))
				{
					UpdateUser(email, username, true, true);
				}

				//Then go on to roadkill handling, get user to get id, set auth cookie
				try
				{
					User user = Repository.GetUserByEmail(email);
					if (user != null)
					{
						bool isFormsAuthEnabled = FormsAuthenticationWrapper.IsEnabled();
						if (isFormsAuthEnabled)
						{
							FormsAuthentication.SetAuthCookie(user.Id.ToString(), true);
						}
						return true;
					}
				}
				catch (DatabaseException ex)
				{
					throw new SecurityException(ex, "An error occurred authentication user {0}", email);
				}
            }
            return false;
        }

        private bool UpdateUser(string email, string username, bool isAdmin, bool isEditor)
        {
            try
            {
                User user = Repository.GetUserByUsername(username);
                if (user == null)
                {
                    return false;
                }
                else
                {
                    if (email != user.Email)
                    {
                        var existingEmailUser = Repository.GetUserByEmail(email);
                        if (existingEmailUser != null && existingEmailUser.Username != username)
                        {
                            throw new SecurityException(null, "The email provided already exists.");
                        }
                        user.Email = email;
                    }
                    user.IsAdmin = isAdmin;
                    user.IsEditor = isEditor;
                    Repository.SaveOrUpdateUser(user);
                    return true;
                }
            }
            catch (DatabaseException ex)
            {
                throw new SecurityException(ex, "An error occurred while updating the user {0}", email);
            }
        }
    }
}

The users will be stored in the Roadkill database, and updated on every login.

Put your dll in binPluginsUserService

Edit Roadkill.config to use your service:

userServiceType=”MyCustomUserService.MyCustomUserService”