.NET Core Multiple Authentication–Windows AD, Azure AD, Database

I was having a project about how to do in .NET Core multiple authentication: Windows AD, Azure AD, Database – and integrate with Roles.

It was an interesting project – and I decide to not make everything – but to construct on an existing project.

The most promising sounds IdentityServer – with the Federation Gateway. : http://docs.identityserver.io/en/latest/topics/federation_gateway.html

So I decided to give a twist , and after many readings and searching , I have found https://github.com/damienbod/AspNetCoreWindowsAuth . It was pretty amazing  – however, some problems occurred.

 

External Integration – with local Active Directory

See in Startup.cs the following

    services.Configure<IISOptions>(iis =>
        {
            iis.AuthenticationDisplayName = "Windows";
            iis.AutomaticAuthentication = true;
        });

When the user clicks the Windows authenticatio the following code is called

public class AccountController : Controller
{
    //ommitted code
    [HttpGet]
    public async Task<IActionResult> ExternalLogin(string provider, string returnUrl)
    {
        if (AccountOptions.WindowsAuthenticationSchemeName == provider)
        {
            // windows authentication needs special handling
            return await ProcessWindowsLoginAsync(returnUrl);
        }
        //ommitted code
    }
    //ommitted code
    private async Task<IActionResult> ProcessWindowsLoginAsync(string returnUrl)
        {
            // see if windows auth has already been requested and succeeded
            var result = await HttpContext.AuthenticateAsync(AccountOptions.WindowsAuthenticationSchemeName);
            if (result?.Principal is WindowsPrincipal wp)
            {
                //ommitted code
            }
            else
            {
                // trigger windows auth
                // since windows auth don't support the redirect uri,
                // this URL is re-triggered when we call challenge
                return Challenge(AccountOptions.WindowsAuthenticationSchemeName);
            }
        }
}

External Integration – with Azure Active Directory

This was by far the most complicated
As a pre-requisites , we need to configure the Azure Active Directory and grab the client Id for the application.

The code in the startup.cs os

        services
        .AddAuthentication(IISDefaults.AuthenticationScheme)
        .AddOpenIdConnect("aad", "Sign-in with Azure AD", options =>
        {
            //options.Authority = $"https://login.microsoftonline.com/common/v2.0/";
            //options.Authority = $"https://ignatandreiyahoo.onmicrosoft.com";
            //options.Authority = $"https://login.windows.net/{tenantId}";
            options.Authority = "https://login.microsoftonline.com/common/v2.0/";
            options.ClientId = $"{clientId}";
            //options.RequireHttpsMetadata = true;
            options.RemoteAuthenticationTimeout = new System.TimeSpan(0,1,58);

            options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
            options.SignOutScheme = IdentityServerConstants.SignoutScheme;

            options.ResponseType = OpenIdConnectResponseType.IdToken; //"id_token";
            options.CallbackPath = "/signin-aad";
            options.SignedOutCallbackPath = "/signout-callback-aad";
            options.RemoteSignOutPath = "/signout-aad";

            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = false,
                //ValidAudience = "f59d5739-1ec9-46fc-961d-b01ef6fb3c51",

                NameClaimType = "name",
                RoleClaimType = "role"
            };
            options.Events.OnRemoteFailure = (context) =>
            {
                string s = context.ToString();
                return Task.CompletedTask;
            };
        })

        ;
        services.AddOidcStateDataFormatterCache("aad");
   

And the code that retrieves the user is:

public class AccountController : Controller
{

    [HttpGet]
    public async Task<IActionResult> ExternalLoginCallback()
    {
        //ommitted code
        // read external identity from the temporary cookie
        var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);
        if (result?.Succeeded != true)
        {
            result = await HttpContext.AuthenticateAsync("aad");
            if (result?.Succeeded != true)
            throw new Exception("External authentication error");
        }

        // lookup our user and external provider info
        var (user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);
        //ommitted code
    }
    //ommitted code
    private async Task<(ApplicationUser user, string provider, string providerUserId, IEnumerable<Claim> claims)> 
        FindUserFromExternalProviderAsync(AuthenticateResult result)
    {
        var externalUser = result.Principal;

        // try to determine the unique id of the external user (issued by the provider)
        // the most common claim type for that are the sub claim and the NameIdentifier
        // depending on the external provider, some other claim type might be used
        var userIdClaim = externalUser.FindFirst(JwtClaimTypes.Subject) ??
                          externalUser.FindFirst(ClaimTypes.NameIdentifier) ??
                          throw new Exception("Unknown userid");

        // remove the user id claim so we don't include it as an extra claim if/when we provision the user
        var claims = externalUser.Claims.ToList();
        claims.Remove(userIdClaim);

        var provider = result.Properties.Items["scheme"];
        var providerUserId = userIdClaim.Value;

        // find external user
        var user = await _userManager.FindByLoginAsync(provider, providerUserId);

        return (user, provider, providerUserId, claims);
    }
    

Configure Azure Active Directory

This implies to go to portal.azure.com.

First you create a new application in the Azure Active Directory

Please retain the applicationId in order to put to the code

    options.ClientId = $"{clientId}";
    

Do not forget about checking the token on authentication

because of this code

    options.ResponseType = OpenIdConnectResponseType.IdToken; //"id_token";
//ommitted code
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = false,
        //ValidAudience = "f59d5739-1ec9-46fc-961d-b01ef6fb3c51",

        NameClaimType = "name",
        RoleClaimType = "role"
    };

Roles for Windows


In Computer Management, I define the user : testUser that belongs to MyGroup

In startup.cs I define the Policy for this:

services.AddAuthorization(options =>
            {
                options.AddPolicy("MyGroupPolicy", policy => policy.RequireClaim("role",@"MyGroup"));
            });
    

I also define an Controller that require this policy

public class TestController : Controller
{
	[Authorize(Policy="MyGroupPolicy")]
	public IActionResult Index()
	{
		return Content(" you can see this because you are authorized to see MyGroupPolicy");
	}
}
    

So now if you logon on Windows with testuser, it will require the policy to be satisfied

Now, to understand the code

Read

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-3.1#multiple-policy-evaluation

and

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-3.1


Now some more code:

Transforming Groups to role claims

string pcName = Environment.MachineName;
// add the groups as claims -- be careful if the number of groups is too large
if (AccountOptions.IncludeWindowsGroups)
{
	var wi = wp.Identity as WindowsIdentity;
	var groups = wi.Groups.Translate(typeof(NTAccount));
	
	var roles = groups
		.Select(it=>it.Value)
		.Select(it=> it.StartsWith(pcName +"\\",StringComparison.InvariantCultureIgnoreCase)?
					it.Substring(pcName.Length+1): it)                        
		.Select(x => new Claim(JwtClaimTypes.Role, x));
	id.AddClaims(roles);
}

And putting back to user

[HttpGet]
public async Task<IActionResult> ExternalLoginCallback()
{
//omitted code
	// lookup our user and external provider info
	var (user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);
//omitted code
    var principal = await _signInManager.CreateUserPrincipalAsync(user);

	foreach (var claim in claims)
	{
		additionalLocalClaims.AddRange(claims);
	}
//ommitted code
	await HttpContext.SignInAsync(user.Id, name, provider, localSignInProps, additionalLocalClaims.ToArray());


You can see the code at https://github.com/ignatandrei/identintegra and more documentation at https://ignatandrei.github.io/IdentIntegra/

[ADCES] 11 febr 2020 , Docker for Developers & How to debug in production a memory leak in .NETCORE3.1

Today,

Docker for Developers & How to debug in production a memory leak in .NETCORE3.1

 

The meeting is at 19:00 and can be found here:

Docker for Developers & How to debug in production a memory leak in .NETCORE3.1

Tuesday, Feb 11, 2020, 7:00 PM

EY Romania
Bulevardul Ion Mihalache 15-17 București, RO

40 Members Attending

Presentation 1: Title: Docker for Developers Presenter: Andrei Ignat, http://msprogrammer.serviciipeweb.ro/ Description: The old mode of downloading and installing software ( SqlServer, Mongo, Rabbit, even frameworks as Angular and .NET Core) will be soon of the past memory. If you want to join the new wave , see how Docker can easy your work as a …

Check out this Meetup →

Docker for Developers crash course

Who is addressed to

This tutorial is aimed to programmers that what to automate the infrastructure surrounding their application. It will contain practical examples of how to improve your application with Docker infrastructure.

The class will be taken by Andrei Ignat, former C# MVP for 6 years, https://forums.asp.net moderator and OpenSource contributor( you can find his AspNetCoreImageTagHelper mentioned on https://github.com/aspnet/Mvc ). More details at his blog at http://msprogrammer.serviciipeweb.ro .

What it contains

Day 1 –Docker basics

Docker starters

– images

– containers

Examples:

Docker for Databases – SqlServer, Mongo

Docker for messaging – RabbitMq

Docker for Applications – .NET Core, Angular

Docker CLI commands

Docker File

Docker-Compose File and CLI for orchestration

Day 2 –Docker

Docker for CI / CD

– automated reproducible building

– automated reproducible testing

Visual Studio Code and Docker

Architecture of Applications with Docker

Crash Course on Angular

Who is addressed to

This tutorial is aimed to HTML/Javascript/CSS programmers with at least 6 months experience. This will help them to build application with Angular.

The class will be taken by Andrei Ignat, former C# MVP for 6 years, https://forums.asp.net moderator and OpenSource contributor( you can find his AspNetCoreImageTagHelper mentioned on https://github.com/aspnet/Mvc ). More details at his blog at http://msprogrammer.serviciipeweb.ro .

What it contains

Day 1 – start Angular

You will code Tour of Heroes Application. You will be helped if need arises with the code , questions and more

Day 2  – Angular advanced

Observables , marbles and RxJS

Http Interceptors

Passing data via components – services

GUI – Pipes, Forms,

Saving/Reading  data to/from backend -with .NET Core

Deploy – environments

 

Crash Course on .NET Core 3.0

Who is addressed to

This tutorial is aimed to C# programmers with at least 6 months experience. Also , they should  have at least 6 months experience with HTML / CSS / Javascript .. This will help them to understand  .NET Core 3 and how to build applications with the .NET Core framework

The class will be taken by Andrei Ignat, former C# MVP for 6 years, https://forums.asp.net moderator and OpenSource contributor( you can find his AspNetCoreImageTagHelper mentioned on https://github.com/aspnet/Mvc ). More details at his blog at http://msprogrammer.serviciipeweb.ro .

What it contains

Day 1

  1. .NET Core, .NET Standard, .NET Framework
  2. Some C# advanced
  3. C# 8-9 what’s new
  4. .NET Core 3 what’s new
  5. .NET Core backend – BL, DAL, Security, tests
  6. EF – console, ASP.NET Scaffolding
  7. ASP.NET Core – Heads up

 

Day 2

  1. Demo Why DI
  2. Anatomy of ASP.NET Core
  3. Plugin Architecture
  4. Winform / windows service / webapi
  5. Arhitectura html+webapi demo

 

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.