LDAP Authentification through Xamarin.Forms (MAUI)

LDAP Authentification through Xamarin.Forms (MAUI)

Allow your application to reuse enterprise internal authentification system hosted on an LDAP Directory Server

Authentification is a crucial part of an application when it comes to giving access to trusted users through our application, and there are different ways to achieve this goal regarding the context in which our application is running.

You may need to build a mobile application requiring to authenticate users inside an internal network using an LDAP directory such as Active Directory, and in this scenario, we need to use LDAP Protocol to operate with the corresponding LDAP directory through our app.

What do you mean by LDAP Authentification?

LDAP, the Lightweight Directory Access Protocol, is a mature, flexible, and well-supported standards-based mechanism for interacting with directory servers. It’s often used for authentication and storing information about users, groups, and applications, but an LDAP directory server is a fairly general-purpose data store and can be used in a wide variety of applications.

In nutshell, when talking about LDAP Authentification we've mainly three actors :

image.png

Implementation

In our case, we're dealing with a cross-platform application running on Xamarin.Forms, and you can apply the same process throughout an MAUI application, as you can also implement this LDAP Authentification code in all platforms that are supporting .NET Standard.

The first step after creating your Xamarin.Forms application is to add the Novell.Directory.Ldap.NETStandard to the Xamarin.Forms standard project.

Authentification State Enumeration

We will use this enumeration to qualify the authentification status after calling the LDAP Protocol, so you can create this enumeration in your project and forward with the next step.

public enum AuthentificationState
{
        InvalidCredential,
        NoConnectionToInternalNetwork,
        NoConnection,
        ValidCredential,
        UnknownReason,
        ConnectedOnline,
        ConnectedOffline
}

Global Setting files

In this post, we'll store all global settings through a static class called GlobalSetting.cs that will contain the LDAP Server Host Name and the LDAP Server Port that you can get from your system administrator if doesn't have it.

You can replace all xxxx by real address and port.

public static class GlobalSetting
    {
#if RELEASE
        public static string LdapServerHostName { get; } = "xxx.xxx.xxx.xxx";
        public static int LdapServerPort { get; } = xxxx;
#endif

#if DEBUG
        public static string LdapServerHostName { get; } = "xxx.xxx.xxx.xxx";
        public static int LdapServerPort { get; } = xxxx;
#endif
    }

LoginViewModel

In the LoginViewModel define a method called ConnectUser() that will be responsible for user authentification to the LDAP Directory Server using the mail address and the corresponding password registered in the domain.

private Task<AuthentificationState> ConnectUser(string email, string password)
{
            if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
                return Task.FromResult(AuthentificationState.InvalidCredential);

            if (Connectivity.NetworkAccess != NetworkAccess.Internet
                && Connectivity.NetworkAccess != NetworkAccess.Local
                && Connectivity.NetworkAccess != NetworkAccess.ConstrainedInternet)
            {
                return Task.FromResult(AuthentificationState.NoConnection);
            }

            try
            {
                using (var cn = new LdapConnection())
                {
                    cn.ConnectionTimeout = 1500;
                    cn.Connect(GlobalSetting.LdapServerHostName, GlobalSetting.LdapServerPort);
                    cn.Bind(email, password);

                    if (cn.Connected)
                        return Task.FromResult(AuthentificationState.ValidCredential);
                };
            }
            catch (LdapException ex)
            {
                switch (ex.ResultCode)
                {
                    case 0:
                        return Task.FromResult(AuthentificationState.ValidCredential);
                    case 91:
                        return Task.FromResult(AuthentificationState.NoConnectionToInternalNetwork);
                    case 49:
                        return Task.FromResult(AuthentificationState.InvalidCredential);
                }
            }
}

Get more informations