NuGet / NuGetGallery

NuGet Gallery is a package repository that powers https://www.nuget.org. Use this repo for reporting NuGet.org issues.
https://www.nuget.org/
Apache License 2.0
1.55k stars 643 forks source link

Azure AD B2C Support #5774

Closed elvogel closed 6 years ago

elvogel commented 6 years ago

Hello,

I'm working on a NuGetGallery implementation that's read-only to users who must register and log in through Azure AD B2C. Is there a way to get the AD B2C authentication up and running fairly quickly? I see there's support for Azure AD, so I would imagine it would only take a bit more configuration settings etc. in order to make this happen. Happy to implement this myself, but I could definitely use some guidance - there's a lot of engineering in these authentication modules. Thanks!

shishirx34 commented 6 years ago

@elvogel - Is this for a specific azure AD tenant or do you want to allow access for any AzureAD tenant. I am assuming you do not want to allow access to your NuGetGallery implementation for Personal MSFT accounts?

The gallery uses Azure AD common endpoint for authentication. This authenticates users with Company or Personal Microsoft accounts, both.

To get integration with Azure AD, you should update the values for AADv2 configs in web.config

Steps

If you need to only allow a certain tenant, or only company accounts. You will need to update the source code. The relevant changes can be found here.

Let me know if that is helpful.

elvogel commented 6 years ago

While similar, Azure AD B2C has a number of differences in the way it handles things. For starters, it will act as the go-between for integrating against Microsoft accounts as well as LinkedIn, Amazon, Facebook, and others. It does use an AD endpoint, its' not the 'common' endpoint, and you have to set it up with policies and the like. Most importantly, I have users in a B2C tenant that I need to plug into a NuGet gallery, so it's critical for me right now...

More information can be found at the documentation here: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-overview

It appears to me that it would involve adding another Authenticator object to the project (say, AzureActiveDirectoryBCAuthenticator for example) with its own configuration and the like. Again, similar to the other Azure AD components, but one where you can tell it to register/authenticate/logout a user...

If that's the case (and I'm assuming it is), is there a getting started guide for creating a custom Authenticator implementation?

Thanks again!

shishirx34 commented 6 years ago

Ah, I see. I am afraid, we don't have any documentation for the authenticator extension as such right now. You should look at the AADv2 provider code and extend the Authenticator class in the similar way for your required B2C provider.

elvogel commented 6 years ago

(If it's okay I'll post my technical questions about the implementation here. If there's a forum you have for these kinds of things let me know and I'll post there instead, or wherever you'd prefer)

So I have an AzureActiveDirectoryB2CAuthenticator and an AzureActiveDirectoryB2CAuthenticatorConfiguration created based on the AzureDirectoryV2 classes. You can see them at https://github.com/endpointsystems/NuGetGallery/tree/master/src/NuGetGallery/Authentication/Providers/AzureActiveDirectoryB2C .

I'm running into an issue in the AuthenticationService.ReadExternalLoginCredential with the following line:

  Authenticator authenticator = Authenticators
                .Values
                .FirstOrDefault(a => a.IsProviderForIdentity(externalIdentity));

The Authenticators property has my B2C authentication in it - I believe there's six total - but it seems to skip over it in this LINQ query. In fact, when I set a breakpoint in the Authenticator.IsProviderForIdentity method I only see it hit four out of the six items in the Authenticators. I can't seem to find the control mechanism for this to either make it go through all six, or to make it go directly to just the B2C authentication, which is all I want to use.

How do I manage this? Thanks!

shishirx34 commented 6 years ago

FirstOrDefault will return after the first value that matches the given provider(returns true for IsProviderForIdentity). Can you iterate all the Authenticators values you have, if one of them matches the externalIdentity it won't go through the remaining authenticators. Can you check if that is the case? Which other external authenticators do you have enabled?

PS: for your authenticator it should hit the IsProviderForIdentity that you have added here(not the base class): https://github.com/endpointsystems/NuGetGallery/blob/master/src/NuGetGallery/Authentication/Providers/AzureActiveDirectoryB2C/AzureActiveDirectoryB2CAuthenticator.cs#L97

elvogel commented 6 years ago

You're right, it was the B2C authenticator.

I'm almost there, with two issues left. The first one I'm having - when I authenticate against the B2C directory, I get prompted to register. When I put in a username and click the Register button, I get a HTTP 401 on the https://localhost/account/Thanks url. I'm a little stumped as to why that's happening.

I'm also noticing that the registration works and I have a record in the Users and Credentials tables, but when I go to sign in again I keep seeing the 'Sign In' link. I'm wondering if maybe it's because I need to confirm the email address?

Thanks!

shishirx34 commented 6 years ago

I am afraid, I won't be able to help you without debugging your scenario. After you register you shouldn't be getting a 401 on /Thanks(given that the registration is successfully created). Perhaps there is some issue during session creation. I would set a breakpoint here: https://github.com/NuGet/NuGetGallery/blob/master/src/NuGetGallery/Controllers/AuthenticationController.cs#L503 and debug step by step to see why you are getting a 401.

Account confirmation is not a requirement for signing into a registered account.(you can debug with the same breakpoint on an account that is already registered but fails to signin)

Note: I am not sure what you are returning for B2CAuthenticator for method SupportsMultiFactorAuthentication, but you might need to return false for your B2CAuthenticator, https://github.com/NuGet/NuGetGallery/blob/master/src/NuGetGallery/Authentication/Providers/AzureActiveDirectoryV2/AzureActiveDirectoryV2Authenticator.cs#L176. Otherwise you might need to add the support for passing the appropriate token values for enforcing 2FA in your authenticator, which I don't think you need to be doing.

elvogel commented 6 years ago

It took a bit of time but I figured it out. Thanks again!

chchin2-dev commented 5 years ago

Lucas, I am trying to do the same thing, using B2C as an authenticator into Nuget.Gallery and running into the same mysterious ghost session where upon registration/login, a session is not established. Are you able to say what the issue was? Thanks!

elvogel commented 5 years ago

It's been a while since I did this, and the libraries have since updated significantly, but I was able to integrate B2C into NuGetGallery successfully by creating a B2C Authenticator that inherits from Authenticator that did what I needed it to do.

chchin2-dev commented 5 years ago

Thanks Lucas for replying. I basically reached across the expanses of the internets to ask you about something you did almost a year and a half ago, lol. I figured it out though and again, I really appreciate you taking the time to reply. In case it is of value to you the issue was that the value in the web.config:

was set to false by default when you clone it down from github. I noticed stepping-in that even external identities ultimately reduce down to a local user context and if that appSetting is set to false, you session never gets created around that local user by nuget gallery which explains why it seems like the user is never logged-in.

Thanks,

Chris


From: Lucas Vogel notifications@github.com Sent: Monday, July 15, 2019 1:10 PM To: NuGet/NuGetGallery Cc: hexchchin2; Comment Subject: Re: [NuGet/NuGetGallery] Azure AD B2C Support (#5774)

It's been a while since I did this, and the libraries have since updated significantly, but I was able to integrate B2C into NuGetGallery successfully by creating a B2C Authenticator that inherits from Authenticator that did what I needed it to do.

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/NuGet/NuGetGallery/issues/5774?email_source=notifications&email_token=AMTZDNZG2DE6XYMBRBAZBWDP7SVRRA5CNFSM4EZR7HJ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZ6LDMI#issuecomment-511488433, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AMTZDN5PTMQMN6IQO67ODX3P7SVRRANCNFSM4EZR7HJQ.