Base solution for your next web application
Open Closed

LDAP authentication plus #3202


User avatar
0
varpippo created

I followed the instructions available here <a class="postlink" href="https://www.aspnetboilerplate.com/Pages/Documents/Zero/User-Management#external-authentication">https://www.aspnetboilerplate.com/Pages ... entication</a> to configure the LDAP authentication and it's working as expected when invoked via:

private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
        {
            var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);

            switch (loginResult.Result)
            {
                case AbpLoginResultType.Success:
                    return loginResult;
                default:
                    throw CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
            }
        }

TryAuthenticateAsync is invoked as expected and it works smoothly, but I'd need to use 2 distinct authentication methods:

  • LdapAuthenticationSource --> TryAuthenticateAsync if userNameOrEmailAddress is an e-mail address OR if it's in the format domain\username
  • The local data (e.g. accounts available in dbo.AbpUsers) otherwise

Is there any way to combine the default authentication mechanism (=without LDAP/External source) with LDAP, based on some conditions?

I mean, is there any way to "chain" different authentication approaches as fallbacks ? As an alternative, is it possible to invoke the "local" authentication from inside TryAuthenticateAsync in case usernameOrEmailAddress is not a valid username/e-mail?


5 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    This is not possible by default but you have two options.

    1. Define your own loginManager whic is derived from AbpLoginManager and ovverride LoginAsync method to do this.
    2. Define an external auto source for example MixedExternalAuthSource (you can find a better name :)), and call Ldap and Local auth sources conditionally in it. <a class="postlink" href="https://aspnetboilerplate.com/Pages/Documents/Zero/User-Management#external-authentication">https://aspnetboilerplate.com/Pages/Doc ... entication</a>

    Thanks.

  • User Avatar
    0
    varpippo created

    Hi!

    Thank you for your feedback :idea:

    I managed to implement it as follows:

    1. In the Web project GetLoginResultAsync invokes:
    var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName, false);
    
    1. TryAuthenticateAsync takes this actions:
    • It tries to understand if userNameOrEmailAddress is a valid&known e-mail or domain\username
    • Invokes ValidateCredentials only if userNameOrEmailAddress exists in AD
    • In all other cases it returns false
    1. var loggedInFromExternalSource = await TryLoginFromExternalAuthenticationSources(userNameOrEmailAddress, plainPassword, tenant);

    can be either true (the authentication through LDAP went fine) or false (userNameOrEmailAddress is invalid / not existing). If it's false the default LoginAsyncInternal method is smart enough to attempt an "internal" authentication:

    return await CreateLoginResultAsync(user, tenant);
    

    I hope that helps someone ;)

    PS. I implemented CreateUserAsync to store in dbo.AbpUsers information like Username/Mail/First name/Last name obtained from AD and it works perfectly, but I'm not sure if it makes sense to have a UpdateUserAsync like this in the class derived from LdapAuthenticationSource:

    public async override Task UpdateUserAsync(User user, Tenant tenant)
            {
                await Task.Run(() => { }); // Nothing to do for the time being. LastLoginTime and other fields are updated automatically?
            }
    

    We don't want to update users created with AuthenticationSource = LDAP

  • User Avatar
    0
    varpippo created

    Using the approach described above we allow the users to login using one of the following options:

    LDAP:

    • Valid AD e-mail address and AD password
    • Valid AD domain\username and AD password
    • Valid AD username and AD password

    if the authentication fails, a last attempt is made:

    LOCAL DATABASE:

    • Valid combination of username / password ( Configuration.MultiTenancy.IsEnabled is commented out, so hopefully we disabled multi-tenancy :) )

    We really appreciate the design behind ASP.NET Boilerplate! 8-)

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @VarPippo,

    Thank you very much for sharing your solution and detailed explanation :). The reason for UpdateUserAsync is, information of user on Ldap might change.

    User can move to another group, can get married and have a different surname :) etc..., but you don't have to use it.

    Thanks again.

  • User Avatar
    0
    varpippo created

    Thank you!

    We're storing some basic details in AbpUsers with CreateUserAsync , but essentially we need only a standardized format of the username: regardless to what is used for the first login (username, domain\username, e-mail), we convert the username to the AD username. Some additional details like first name and last name are retrieved and stored, but we're not using them in any way.

    So, as long as, having an "empty" UpdateUserAsync method does not create any issues to ASP.NET Boilerplate inner mechanisms, I'm fine with that! :D