locked
Windows Authentication in ASP.NET Core with Kestrel On Linux Plateform RRS feed

  • Question

  • User207833854 posted

    Hello,
    I am not a developer but I work with others on the implementation of windows authentication in net.core on Linux platform. Apparently, this is now possible directly with Kestrel in version 3 preview
    So I tried, but without success. However, I followed the official MS documentation

    "https://docs.microsoft.com/fr-fr/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio=aspnetcore-3.0&tabs=visual-studio"

    I tried the SDK 3.0 on two linux VMs, one in Debian 10 and the other in centOS 7.6.

    I have configured my krb5.conf file correctly

    I have registered my VM on my AD domain with success

    I created a dot.net project with the command "dotnet new webapp --auth Windows".

    I added the package "dotnet add package Microsoft.AspNetCore.Authentication.Negotiate --version 3.0.0-preview6.19307.2"

    I created my SPN and keytab

    setspn -S HTTP/mywebservice.coolcorp.priv pocvm

    setspn -S HTTP/mywebservice@COOLCORP.COM pocvm

    ktpass -princ HTTP/mywebservice.coolcorp.priv@COOLCORP.PRIV -pass myKeyTabFilePassword -mapuser COOLCORP\pocvm$ -pType KRB5_NT_PRINCIPAL -out c:\temp\pocvm.HTTP.keytab -crypto AES256-SHA1

    When I test my keytab with the kinit command, it works.
    kinit HTTP/mywebservice.coolcorp.priv@COOLCORP.PRIV -k -t /etc/keytab/pocvm.HTTP.keytab

    I do have a kerberos ticket.

    I set the location of my keytab as an environment variable.
    export KRB5_KTNAME=/etc/keytab/pocvm.HTTP.keytab

    I updated the startup file

    namespace pocdotnet
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                    options.CheckConsentNeeded = context => true;
                });
            services.AddMvcCore(options =>
        {
            options.EnableEndpointRouting = false; // TODO: Remove when OData does not causes exceptions anymore
        });
    
                services.AddRazorPages();
                services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
       .AddNegotiate();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                    app.UseHsts();
                }
    
                app.UseAuthentication();
                app.UseMvc();
                app.UseHttpsRedirection();
                app.UseStaticFiles();
    
                app.UseCookiePolicy();
    
                app.UseRouting();
    
                app.UseAuthorization();
    
    
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapRazorPages();
                });
            }
        }
    }
    

    I launch my application: dotnet run

    But when I display my site "mywebservice.coolcorp.priv", my username does not appear next to Hello.

    Does anyone have any ideas or could they help me?

    Thursday, July 11, 2019 11:39 AM

All replies

  • User-474980206 posted
    The account running Kestrel must be a windows domain account and have a Kerberos ticket.
    Thursday, July 11, 2019 2:16 PM
  • User207833854 posted

    Thanks for your help.

    I have created a service account in AD. "svc_dev_dck"

    I regenerated the SPNs and the keytab.

    setspn -S HTTP/devdncweb501.coolcorp.priv:8081 svc_dev_dck
    setspn -S HTTP/devdncweb501@COOLCORP.PRIV:8081 svc_dev_dck
    ktpass -princ HTTP/devdncweb501.coolcorp.priv:8081@COOLCORP.PRIV -pass MONPASS -mapuser COOLCORP\svc_dev_dck -pType KRB5_NT_PRINCIPAL -out c:\temp\svc_dev_dck.HTTP.keytab -crypto AES256-SHA1

    I connect to the linux server with my account svc_dev_svc_dev_dck@coolcorp.priv

    I have a ticket with the command klist

    Default principal: svc_dev_dck@COOLCORP.PRIV

    Valid starting Expires Service principal
    07/12/2019 14:30:52 07/13/2019 00:30:52 krbtgt/COOLCORP.PRIV@COOLCORP.PRIV
    renew until 07/19/2019 14:30:42

    I launch my dotnet application....But the problem remains the same :

    I don't have the user's name when I log in to http://devdncweb501.coolcorp.priv:8081

    Friday, July 12, 2019 12:41 PM
  • User-474980206 posted
    Did you mark the controller as requiring authorization. Check the browser network trace. you should get getting a 401 with WWW-Authenticate: Negotiate header, otherwise your site is anonymous.
    Friday, July 12, 2019 3:55 PM
  • User207833854 posted

    Hi

    Thank you for your help. I approached a developer who provided me with a new version of the code based on a new model "dotnet new mvc --auth Windows"

    An authentication request has been forced but it does not work. The authentication window runs in a loop.

    Here is the Startup.cs code :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.HttpsPolicy;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.AspNetCore.Authentication.Negotiate;
    using Microsoft.AspNetCore.Authorization;
    
    namespace devapp
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                    options.CheckConsentNeeded = context => true;
                });
    
    
                services.AddControllersWithViews();
                services.AddRazorPages();
    	    services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
                services.AddAuthorization(options =>
                {
                    options.AddPolicy("DiagnosticsRole", p =>
                        p.Requirements.Add(new SecurityGroupsRequirement()));
                });
                services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
    
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                    app.UseHsts();
                }
    
                app.UseHttpsRedirection();
                app.UseStaticFiles();
    
                app.UseCookiePolicy();
    
                app.UseRouting();
    
                app.UseAuthorization();
    	    app.UseAuthentication();
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Home}/{action=Index}/{id?}");
                    endpoints.MapRazorPages();
                });
            }
        }
    }
    

    Here is the HomeController.cs code :

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using devapp.Models;
    using Microsoft.AspNetCore.Authorization;
    
    namespace devapp.Controllers
    {
    	[Authorize]
        public class HomeController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
    
            public IActionResult Privacy()
            {
                return View();
            }
    
            [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
            public IActionResult Error()
            {
                return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
            }
        }
    }
    

    The strange thing is that I capture the traffic between my server and the domain controller, I don't see any communication.

    When I use the "inotifywait -m" command to monitor access to my keytab file, I do not observe any activity.
    I have the impression that the variable "KRB5_KTNAME" is totally ignored

    Monday, July 15, 2019 9:50 AM
  • User-626103491 posted

    Hi,

    i am trying since several days to get this running. Did you solve the problems? Did you get it running?

    best regards

    Stefan

    Tuesday, December 17, 2019 5:44 PM
  • User1848502626 posted

    Hi, 

    We're trying to achieve it with a docker linux container - our problems are really similar to yours and basically this thread was the best example for us to start (thanks for that really much! )..

    we're getting 401 continuously, it seems like it just doesn't even trying to use our kerberos ticket.

    Our base first problem is, that we're not sure if/and how to run the dotnet application by the the user what is for the SPN (inside the docker image/container). We've added a user similar to the one able to use the SPN but it is just doesn't seems to be the Windows AD user...

    Does anyone have any idea how to continue or what to try? I think with .net 3.0 is out it should be no problem to use Asp.Net integrated window authentication from linux through kerberos (at least the official microsoft page says it should work), but there is no complete walkthrough yet...

    Thank you,
    Colosh

    Friday, February 21, 2020 11:55 AM
  • User-474980206 posted

    there are two use cases for kerberos. 

    1) the asp.net core application to request a windows resource such as sqlserver using windows authentication. This requires installing kerberos client and running kinit before running asp.net core application.  see:

       https://docs.microsoft.com/en-us/sql/azure-data-studio/enable-kerberos?view=sql-server-ver15

    2) the asp.net core application authenticates the user using windows authentication. This is a more complex issue as the linux server must be added to the domain as a known server.  see this link:

      https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio

    the domain controller must be able to verify the the dns name of the linux server. also be sure both server are accessing the same kerberos ticket server.

    Friday, February 21, 2020 4:04 PM
  • User-454115025 posted

    Hi Bruce,

    I have exactly the same use-case where I want to connect my ASP .Net Core 3 web application to a SQL server that requires windows AD based authentication.

    I have dockerized this:  on my Linux machine and it produces this Output:

    warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
          Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
    info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]
          User profile is available. Using '/root/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
    info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[58]
          Creating key {xxxxx-2d58-4388-xxxx-zzzz} with creation date 2020-05-15 15:40:54Z, activation date 2020-05-15 15:40:54Z, and expiration date 2020-08-13 15:40:54Z.
    warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
          No XML encryptor configured. Key {xxxxx-2d58-4388-xxxx-zzzz} may be persisted to storage in unencrypted form.
    info: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[39]
          Writing data to file '/root/.aspnet/DataProtection-Keys/key-xxxxx-2d58-4388-xxxx-zzzz.xml'.
    info: Microsoft.Hosting.Lifetime[0]
          Now listening on: http://0.0.0.0:80
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info: Microsoft.Hosting.Lifetime[0]
          Hosting environment: Production
    info: Microsoft.Hosting.Lifetime[0]
          Content root path: /app/

    Now, I am totally lost as to how and where i need to specify Windows AD credentials (username/password) for my SQL Server and test whether my application can connect to it or not?

    Is there any code example that can help me out?

    Thanks. 

       

    Friday, May 15, 2020 4:20 PM
  • User-474980206 posted

    if you have asp.net core running in a docker container, and want to use trusted security to connect to sqlserver you need to implement a couple features.

    • sqlserver should be configured for kereberos. see docs to create the SPN. 
    • you need to install kerberos in the docker container. the docker kerberos should be configured to use the same kerberos ticket server as sqlserver (typically a domain controller). you can connect to the docker container and run kinit to verify all is configured correctly.
    • in the docker container, before running the asp.net core app, you should run kinit with the user name / password that you want asp.net core to connect with. 
    Friday, May 15, 2020 6:39 PM
  • User-454115025 posted

    Hi Bruce,

    Sorry for replying late, i was on vacation.

    So regarding:

    >>sqlserver should be configured for kereberos. see docs to create the SPN. 

    I am planning to follow: https://systemscenter.ru/smsv4.en/html/d2070756-bb89-4319-bd5c-8cc74a05a6f1.htm#:~:text=From%20the%20command%20line%2C%20navigate,1433%20.

    Regarding this:

    >>you need to install kerberos in the docker container. the docker kerberos should be configured to use the same kerberos ticket server as sqlserver (typically a domain controller). >>you can connect to the docker container and run kinit to verify all is configured correctly.

    How to ensure/configure this: "the docker kerberos should be configured to use the same kerberos ticket server as sqlserver (typically a domain controller)"? Is there any reference code snippet for it?

    Regarding this:

    >>in the docker container, before running the asp.net core app, you should run kinit with the user name / password that you want asp.net core to connect with. 

    is there any code snippet for this specially " run kinit with the user name / password that you want asp.net core to connect with."? And is that the Windows authentication username/password that is to be used to connect to the sql server?

    Many Thanks. 

    Friday, June 5, 2020 11:01 AM
  • User-474980206 posted

    You network admin should know the Kerberos ticket server. 

    knint is a command line utility. Just do a man page of it. 

       https://www.tutorialspoint.com/unix_commands/kinit.htm

    After installing in you docker container, just connect to the docker console and test it.

    Friday, June 5, 2020 2:57 PM