dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.01k stars 4.67k forks source link

Support for System.DirectoryServices for Windows #14734

Closed syeshchenko closed 4 years ago

syeshchenko commented 9 years ago

Execution plan:

If anyone is working on any step, please mention it & coordinate here to avoid duplicated effort. @karelz will co-assign the issue to you as well.


Original proposal

Hello there, I was wondering if there is a chance to add support for System.DirectoryServices in CoreCLR.

In one of our projects we are trying to implement GAL based authentication on Linux and tried to use Mono for this task, however it only works partially, check for IsUserInGroup fails. This is something similar to what we are trying to get working: http://stackoverflow.com/questions/2188954/see-if-user-is-part-of-active-directory-group-in-c-sharp-asp-net

So I was hoping that with the addition of this namespace to CoreCLR, it might solve our problem!

Thank you

danroth27 commented 8 years ago

@vibronet

NickCraver commented 8 years ago

Is there any update on this?

Eaglef90 commented 8 years ago

I too would like an update on this. My company is having me build a new app that requires the ability to query Active Directory via LDAP but it appears this is currently not possible. Is there planed support for it, is it being dropped in favor of something else, or is it already working just not documented anywhere?

jozefizso commented 8 years ago

A new, fresh look at implementing the LDAP and Active Directory support would be great to have in .NET CoreFX.

coe-jeubanks commented 8 years ago

We really need an Active Directory/LDAP solution we can leverage in .NET Core. Whether it's a clean sheet implementation or a port of System.DirectoryServices doesn't matter as much to me. There are a lot of business-focused Windows applications that absolutely need AD auth, and LDAP auth would be a great feature bullet point for cross-platform developers.

NickCraver commented 8 years ago

Agreed on the backwards compatible notes above - I don't feel a direct port is needed really, we just need a way to access auth (and perform other actions: search, unlock, delete, etc.) against Active Directory or any LDAP provider.

terrajobst commented 8 years ago

@NickCraver

I don't feel a direct port is needed really, we just need a way to access auth [...] against Active Directory

That's good to know. Don't read too much into my port-to-core label I just applied. It's just my way of tracking gaps in the .NET Core offering that prevents customers like you from porting their app to .NET Core.

NickCraver commented 8 years ago

@terrajobst Gotcha. I don't necessarily think this has to be a 1.0 item because of its modularity (and it sounds like it's slated for post-RTM anyway), but I do look forward to it. It'll be a blocker on porting Opserver for me, so happy to participate in API discussions if we can be of use. We have a wide range of use cases on the sysadmin side of things that may be helpful, ping if I can help out.

sqmgh commented 8 years ago

Just to throw another hat into the ring. At the moment this is the biggest blocker left for me as well. Simply being able to auth would be a huge help for now.

Eaglef90 commented 8 years ago

Can we get an official response from someone on the dev team on the plans for this, if there are even any plans at all to support this?

ghost commented 8 years ago

I don't feel a direct port is needed really

Why? Sorry I am confused. Wouldn't that be the most easiest solution for everyone and in accord with DRY principle? Nevertheless, if there is a reason to write the entire API from scratch, some consistency with old API (same method signatures) would be less confusing for consumer.

NickCraver commented 8 years ago

@jasonwilliams200OK let me clarify, I really meant DirectoryServices.ActiveDirectory specifically. I think authentication, and the stuff around it: e.g. group membership is the 95-99% use case of the namespace. I think a direct port of signatures of that is pretty useful. If the rest warrants change for some reason then I'd be pretty okay with that, and okay if it came later...the auth would be good to get out the door ASAP since that's a blocker to many.

saf-itpro commented 8 years ago

Integrating at least a basic functionality of searching Active Directory users and mapping them with custom roles with ASP.NET 5 will ease the implementation of Windows Authentication into ASP.NET web applications. We need this functionality at our intranet site.

Sjark commented 8 years ago

This is a blocker for us as well. We need to be able to auth, query users and groups, create new user and groups etc against a ldap server.

SSiefert commented 8 years ago

It is also a blocker for me - I require quering and authenticating users.

ClintBailiff commented 8 years ago

I came up with a solution for authenticating against Active Directory in a .NET Core rc1 web application. You just have to override the CheckPasswordAsync method in the UserManager class. Let me know what you think.

First you need make a custom register page that allows the user to input an AD username instead of an email address and password. That username goes in the UserName property of the ApplicationUser class that is generated by the ASP.NET 5 template when you chose Individual User Accounts authentication. Also, you'll have to default the Password property to something that passes the internal validation in the IdentityUser class.

My register page controller calls a Web API 2 method that finds the username in AD and returns JSON that holds the AD information for that user. I've added some custom properties to the ApplicationUser class to hold the AD information. I will post the code from my project next week.

Then add a class file in the Services folder. I named mine ApplicationUserManager.cs. Add the code below to that class file.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.OptionsModel;
using [YourApp].Models;

namespace [YourApp].Services
{
    public class ApplicationUserManager : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<ApplicationUser> passwordHasher,
                                      IEnumerable<IUserValidator<ApplicationUser>> userValidators, IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators,
                                      ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger,
                                      IHttpContextAccessor contextAccessor)
        : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger, contextAccessor)
        {

        }

        public override async Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
        {
            //Pass user.UserName and password to an ASP.NET Web API 2 method that 
            //does the Active Directory authentication and returns a bool.
        }
    }
}

Then open the Startup.cs file. Add .AddUserManager() to the AddIdentity call in the ConfigureServices method as shown below.

services.AddIdentity<ApplicationUser, IdentityRole>()
       .AddEntityFrameworkStores<ApplicationDbContext>()
       .AddUserManager<ApplicationUserManager>()
       .AddDefaultTokenProviders();

This at least allows me to setup policy/claims based authorization while waiting for DirectoryServices support.

HB-2012 commented 8 years ago

I rely on this library. It's a shame I can't port now.

NickCraver commented 8 years ago

@ClintBailiff I have to chime in here - because relaying the user's password across the wire again to another application in plaintext is a really bad idea. Please, don't use this approach. It's a security hole.

@terrajobst this will be the blocker in porting my larger applications like Opserver over - can we please get this prioritized?

ClintBailiff commented 8 years ago

@NickCraver I never suggested passing the credentials as plaintext. As a rule I use SSL for all my web applications/services because they typically return data that only authorized users should see. I didn't think to specify that probably because it's so obvious that you would not want to send credentials in plaintext.

PleasantD commented 8 years ago

I would be i support of at least providing a port of System.DirectoryServices.Protocols. We recently switched our LDAP-related code to this to support a larger range of LDAP servers, as the System.DirectoryServices.ActiveDirectory namespace only likes to talk to AD servers.

I suppose, it would be possible for a 3rd party library to spin up this kind of support, but since it already exists in the framework I would imagine that a port would be simpler.

aminebizid commented 8 years ago

WTF asp team is not provide this basic functionality This is a really blocker issue :(

liquidboy commented 8 years ago

Any update on LDAP support in CoreCLR ?

jnssnmrcs commented 8 years ago

I would also like an update on this. I will be developing an enterprise application with ASP.NET Core that needs to authenticate users against an AD-server.

joshfree commented 8 years ago

I'll be looking into porting System.DirectoryServices to .NET Core for v1.1.0 (https://github.com/dotnet/corefx/milestones)

leo9223 commented 8 years ago

@joshfree I also have to authenticate users from ADLDS please also consider System.DirectoryServices.AccountManagement

jchannon commented 8 years ago

A couple of years ago the company I worked for took the Novell (Mono) LDAP library source code so our application could talk to Active Directory, OpenLDAP and Oracle systems, and we added support for paged controls and updated some TLS fixes. We did this as we wanted to run on Linux. A PR with our changes was sent to the owners. As we now want to get onto CoreCLR that library needed converting to RC2. The work has begun here https://github.com/VQComms/CsharpLDAP/pull/1, there are 17 compiler errors left that need addressing. They are mainly Thread.Abort, ThreadInterruptedException, replacing TLS streams from Mono to the CoreCLR SslStream If anyone is interested and needs LDAP support for CoreCLR feel free to help out.

ClintBailiff commented 8 years ago

I have confirmed that an ASP.NET Core Web Application (.NET Framework) RC2 project can reference a class library that uses System.DirectoryServices.AccountManagement. I could only get it to work when both the web application and the class library are created with VS 2015 Update 2 and both use .NET Framework 4.6.1.

h3smith commented 8 years ago

Just to echo sentiments of others, we are dead in the water porting without being able to query LDAP and the like.

ClintBailiff commented 8 years ago

@h3smith See my previous post. With the release of RC2 you can now reference a class library that uses System.DirectoryServices.AccountManagement.

jchannon commented 8 years ago

Not on Netstandard.

However as I say we are working on getting this working. Hopefully have something in around 2-3 weeks

On Friday, 17 June 2016, Clinton Bailiff notifications@github.com wrote:

@h3smith https://github.com/h3smith See my previous post. With the release of RC2 you can now reference a class library that uses System.DirectoryServices.AccountManagement.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/dotnet/corefx/issues/2089#issuecomment-226837679, or mute the thread https://github.com/notifications/unsubscribe/AAGapiY8HNzdakVdStwCFqvReT6kfSTcks5qMt_wgaJpZM4FF2fx .

johnkwaters commented 8 years ago

Any updates on this? I need to authenticate the calling user, when the user is using an angular web app on the LAN, logged in to AD, calling a WebAPI controller method (without the user entering password into web browser) in aspnet core RC2. Possible? Soon possible?

aminebizid commented 8 years ago

To do this you just need to use withCredentials in your http requests from the client. Then you can get user informations and claims in your controllers using User.Identity. This works in ie and chrome but with Firefox a popup will be automatically shown to Le the user type in their windows user and password

dsbenghe commented 8 years ago

We hit the same issue (e.g. trying to use a LDAP server as user store) around two months ago. We could not find any solution besides porting the Novell LDAP library (https://www.novell.com/developer/ndk/ldap_libraries_for_c_sharp.html) to .net core (see here https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard). There is a nuget package published. We are using the library with OpenDJ LDAP server (should work with any LDAP server) - no issues in 1.5 months of usage.

jchannon commented 8 years ago

@dsbenghe we've just got our Novell LDAP lib compiling on netstandard, ours contains paging too. This was done by @igorshmukler . Would you like to compare and collaborate? Ours is WIP here https://github.com/VQComms/CsharpLDAP/tree/coreclrPort

timdows commented 8 years ago

@dsbenghe Thanks for your work on the .NET Core implementation of it. After getting the nuget package I have created the following code to test if the user's ActiveDirectory password is correct

using Novell.Directory.Ldap;

private async Task<JsonResult> LoginActiveDirectory(LoginModel model)
{
    var user = await _userManager.FindByNameAsync(model.Username);
    if (user != null)
    {
        var result = AuthenticateWithActiveDirectory(model.Username, model.Password);
        if(result == string.Empty)
        {
            await _signInManager.SignInAsync(user, false);
            return Json(new LoginResult {Success = true});
        }
        return Json(new LoginResult { Success = false, Message = result });
    }

    return Json(new LoginResult { Success = false, Message = "User not found in local database" });
}

It calls AuthenticateWithActiveDirectory:

private string AuthenticateActiveDirectory(string username, string password)
{
    const int ldapVersion = LdapConnection.Ldap_V3;
    var conn = new LdapConnection();

    try
    {
        conn.Connect(_loginSettings.LdapHost, _loginSettings.LdapPort);
        conn.Bind(ldapVersion, $"{_loginSettings.LdapDomain}\\{username}", password);
        conn.Disconnect();
    }
    catch (LdapException e)
    {
        return e.Message;
    }
    catch (System.IO.IOException e)
    {
        return e.Message;
    }

    return string.Empty;
}

And uses a simple helper class to let the angular application know what is going on

public class LoginResult
{
    public bool Success { get; set; }
    public string Message { get; set; }
}
crutkas commented 8 years ago

For UWP, there is a request for this feature on our UserVoice: https://wpdev.uservoice.com/forums/110705/suggestions/12556779

joshfree commented 8 years ago

cc @tquerec @jimuphaus who will be working on System.DirectoryServices support for .NET Core.

johnkwaters commented 8 years ago

Can't wait! ETA? Design specs?

GArrigotti commented 8 years ago

When it is finally ported over, will we have access to:

using(var context = new PrincipalContext(ContextType.Domain, "Domain"))
     return context.ValidateCredentials("user", "password");

I know there are some minor defects within that namespace, but is still pretty helpful.

dcs619 commented 8 years ago

@GArrigotti in testing, using LdapDirectoryIdentifier is usually faster than PrincipalContext.

using System.DirectoryServices.Protocols;
/////////
try
{
    using (LdapConnection conn = new LdapConnection(new LdapDirectoryIdentifier(domain)))
    {
        conn.Bind(new System.Net.NetworkCredential(username, password, domain));
        return true;
    }
}
catch (LdapException e)
{
    return false;  
}
johnkwaters commented 8 years ago

Is there an ETA? I could use this in a system due to be completed at the end of this month...

ClintBailiff commented 8 years ago

@johnkwaters is there are reason why you can't put the AD code in a class library? Some people (including me) have had problems referencing legacy class libraries in an ASP.NET Core application. But there are no issues if you create the web app and class library in VS 2015 Update 3 and target .NET Framework 4.61 in the web app and class library.

ghost commented 8 years ago

is there are reason why you can't put the AD code in a class library?

Do you mean PCL followed by "imports": "portable-net45+win8" in project.json for .NET Core TxM? That will require Mono PCL Reference Assemblies to be present on Unix and not a "pure donet-core" solution, which grantees self-sufficiency on Unix. It is a good hack to silent the compiler, but only work through and through if the CoreFX BCL have the corresponding implementation. As a rule, the project.json with no "imports" for netcoreapp/netstandard1.x is always better. e.g. https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard/blob/ace2706/Novell.Directory.Ldap.NETStandard/project.json#L11

johnkwaters commented 8 years ago

Any update on an ETA? Where can I go to self service that recurring question?

curi0usJack commented 8 years ago

Really looking forward to this feature!

luislorenzo commented 8 years ago

Really looking forward to this feature too !!

PoppyPham commented 8 years ago

Really looking forward to this feature too !!

zuckerthoben commented 8 years ago

I am also in desperate need for this feature!

orloffm commented 8 years ago

Guys, could you all just add reactions to the main post?

jchannon commented 8 years ago

Or use the libraries that have been put on nuget by 2 separate people. Its all OSS. If you dont like the package, send a PR

On 8 September 2016 at 12:19, Mikhail Orlov notifications@github.com wrote:

Guys, could you all just add reactions to the main post?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/dotnet/corefx/issues/2089#issuecomment-245567328, or mute the thread https://github.com/notifications/unsubscribe-auth/AAGappY2sfk1GWkY7w1IcuAJSa_uKFHwks5qn-8qgaJpZM4FF2fx .