Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to integrate LDAP in WPF application that consumes WCF service

I will start by describing how my application works today without LDAP. I have WPF application that consumes WCF services (authentication windows or UserName depends on users choice). This services allows communication with database.

I display to user a "Login screen" in order to allow him set her "user name" and "password" then application connects to service and consumes function that checks if UserName and Password exist in database. (see img below) enter image description here

Now I need also to integrate LDAP for authenticating user accounts against their existing systems instead of having to create another login account.

I'm bit ignorant about LDAP and confused about many things. Please excuse the possible use of wrong terminology.

I googled but I still don't have answers of many questions.

1- What is the relation between users that exist in my database table "User" and profiles that I should be created in LDAP ?

2- What is the check I should do to allow user come from LDAP to access to my application and use all functionnalities of my service ?

3- Should I have service type "LDAP" like other authentications types I have today in my application ("Windows" and "UserName") ?

4- If I want to update my application architecture described in picture above where should I add LDAP ?

like image 355
xtensa1408 Avatar asked Dec 10 '17 00:12

xtensa1408


Video Answer


1 Answers

First I am going to answer your questions one by one,

  1. The user on LDAP is the same on DB, you can hold LDAP's Username and it's domain in your Users Table, but the profile on the LDAP may vary with your profile table, but it can be fetched from LDAP address.

  2. It's enough to check username and password over LDAP, just need to hold LDAP addresses in a Table (example ExternalPath) and make a relation between User and ExternalPath tables. LDAP address is contains some specifications.

  3. Yes, you have to have a separate mechanism for identifying LDAP Users which I will explain more further.

  4. This is not hard if everything be atomic and designed right, in further steps you may see it is easy.

So let me tell about my experience in LDAP and Authenticate users on LDAP and DB and our architecture.

I was implemented a WCF service named Auth.svc, this service contains a method named AuthenticateAndAuthorizeUser this is transparent for user which came from LDAP or anywhere.

I hope you get the clue and architecture to Authenticate user over LDAP and DB in below steps:

1- First I have a table named Users which hold users info and one more field named ExternalPath as foreign key, if it is null specify UserName is in DB wit it's password otherwise it is came from UserDirectory.

2- In second step you have to hold LDAP address (in my case LDAP addresses are in ExternalPath table), all LDAP addresses are on port 389 commonly.

3- Implementing authenticate User, if is not found(with Username and Password) then check it's ExternalPath to verify over LDAP address.

4- The DB schema should be something like below screenshot.

enter image description here

As you can see ExternalPath field specify user is from LDAP or not.

5- In presentation layer I am defining LDAP servers like below screenshot also

enter image description here

6- In the other side while adding new user in system you can define LDAP for user in my case I am listing LDAP titles in a DropDown in adding User form (if admin select LDAP address then don't need to get password and save it in DB), as I mentioned just need to hold LDAP username not password.

7- But last thing is authenticating user on LDAP and DB.

So the authenticate method is something like:

User userLogin = User.Login<User>(username, password, ConnectionString, LogFile);
if (userLogin != null)
    return InitiateToken(userLogin, sourceApp, sourceAddress, userIpAddress);
else//Check it's LDAP path
{
    User user = new User(ConnectionString, LogFile).GetUser(username);
    if (user != null && user.ExternalPath != null)
    {
        LDAPSpecification spec = new LDAPSpecification
        {
            UserName = username,
            Password = password,
            Path = user.ExternalPath.Path,
            Domain = user.ExternalPath.Domain
        };
        bool isAthenticatedOnLDAP = LDAPAuthenticateUser(spec);

    }
}

If userLogin does not exist in DB by entered UserName and Password then we should authenticate it over related LDAP address.

In else block find User from Users table and get it's ExternalPath if this field was not null means User is on LDAP.

8- The LDAPAuthenticateUser method is :

public bool LDAPAuthenticateUser(LDAPSpecification spec)
{
    string pathDomain = string.Format("LDAP://{0}", spec.Path);
    if (!string.IsNullOrEmpty(spec.Domain))
        pathDomain += string.Format("/{0}", spec.Domain);
    DirectoryEntry entry = new DirectoryEntry(pathDomain, spec.UserName, spec.Password, AuthenticationTypes.Secure);
    try
    {
        //Bind to the native AdsObject to force authentication.
        object obj = entry.NativeObject;
        DirectorySearcher search = new DirectorySearcher(entry);

        search.Filter = "(SAMAccountName=" + spec.UserName + ")";
        search.PropertiesToLoad.Add("cn");
        SearchResult result = search.FindOne();
        if (null == result)
        {
            return false;
        }
    }
    catch (Exception ex)
    {
        Logging.Log(LoggingMode.Error, "Error authenticating user on LDAP , PATH:{0} , UserName:{1}, EXP:{2}", pathDomain, spec.UserName, ex.ToString());
        return false;
    }
    return true;
}

If exception raised in LDAPAuthenticateUser means User does not exist in User Directory.

The authentication code accepts a domain, a user name, a password, and a path to the tree in the Active Directory.

The above code uses the LDAP directory provider the authenticate method calls LDAPAuthenticateUser and passes in the credentials that are collected from the user. Then, a DirectoryEntry object is created with the path to the directory tree, the user name, and the password. The DirectoryEntry object tries to force the AdsObject binding by obtaining the NativeObject property. If this succeeds, the CN attribute for the user is obtained by creating a DirectorySearcher object and by filtering on the SAMAccountName. After the user is authenticated and exception not happened method returns true means user find on given LDAP address.

To see more info about Lightweight Directory Access Protocol and authenticate over it THIS Link can be useful which tells about specification more.

Hope will help you.

like image 111
Aria Avatar answered Nov 08 '22 13:11

Aria