zoukankan      html  css  js  c++  java
  • Windows Authentication

    Configure Windows Authentication in ASP.NET Core

    Windows Authentication (also known as Negotiate, Kerberos, or NTLM authentication) can be configured for ASP.NET Core apps hosted with IISKestrel, or HTTP.sys.

    Windows Authentication relies on the operating system to authenticate users of ASP.NET Core apps. You can use Windows Authentication when your server runs on a corporate network using Active Directory domain identities or Windows accounts to identify users. Windows Authentication is best suited to intranet environments where users, client apps, and web servers belong to the same Windows domain.

     Note

    Windows Authentication isn't supported with HTTP/2. Authentication challenges can be sent on HTTP/2 responses, but the client must downgrade to HTTP/1.1 before authenticating.

    Proxy and load balancer scenarios

    Windows Authentication is a stateful scenario primarily used in an intranet, where a proxy or load balancer doesn't usually handle traffic between clients and servers. If a proxy or load balancer is used, Windows Authentication only works if the proxy or load balancer:

    • Handles the authentication.
    • Passes the user authentication information to the app (for example, in a request header), which acts on the authentication information.

    An alternative to Windows Authentication in environments where proxies and load balancers are used is Active Directory Federated Services (ADFS) with OpenID Connect (OIDC).

    Windows environment configuration

    The Microsoft.AspNetCore.Authentication.Negotiate component performs User Mode authentication. Service Principal Names (SPNs) must be added to the user account running the service, not the machine account. Execute setspn -S HTTP/myservername.mydomain.com myuser in an administrative command shell.

    Linux and macOS environment configuration

    Instructions for joining a Linux or macOS machine to a Windows domain are available in the Connect Azure Data Studio to your SQL Server using Windows authentication - Kerberos article. The instructions create a machine account for the Linux machine on the domain. SPNs must be added to that machine account.

     Note

    When following the guidance in the Connect Azure Data Studio to your SQL Server using Windows authentication - Kerberos article, replace python-software-properties with python3-software-properties if needed.

    Connect Azure Data Studio to your SQL Server using Windows authentication - Kerberos

    RedHat Enterprise Linux

    Bash
    sudo yum install realmd krb5-workstation
    

    Edit the /etc/sysconfig/network-scripts/ifcfg-eth0 file (or other interface config file as appropriate) so that your AD domain controller's IP address is listed as a DNS server:

    /etc/sysconfig/network-scripts/ifcfg-eth0
    <...>
    PEERDNS=no
    DNS1=**<AD domain controller IP address>**
    

    After editing this file, restart the network service:

    Bash
    sudo systemctl restart network
    

    Now check that your /etc/resolv.conf file contains a line like the following:

    Code
    nameserver **<AD domain controller IP address>**
    
    Bash
    sudo realm join contoso.com -U 'user@CONTOSO.COM' -v
    <...>
    * Success
       

    Windows authentication in linux docker container

    5

    i am trying to use windows authentication in linux docker container under kubernetes.

    I am following this settings: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio#kestrel

    App is in .net core3, with nuget Microsoft.AspNetCore.Authentication.Negotiate and running in kestrel

    I have added the

    services.AddAuthentication(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateDefaults.AuthenticationScheme).AddNegotiate();
    

    as well as

    app.UseAuthentication();
    

    and setup my devbase image as

    FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster as final
    USER root
    RUN whoami
    RUN apt update && apt dist-upgrade -y
    
    ADD ca/ca.crt /usr/local/share/ca-certificates/ca.crt
    RUN chmod 644 /usr/local/share/ca-certificates/*
    RUN update-ca-certificates
    
    
    RUN DEBIAN_FRONTEND=noninteractive apt install -y krb5-config krb5-user
    
    COPY krb5.conf /etc/krb5.conf
    RUN mkdir /app
    
    RUN echo BQIAAA..== | base64 -d > /app/is.k01.HTTP.keytab
    WORKDIR /app
    
    #RUN docker version
    
    RUN groupadd --gid 1000 app && useradd --uid 1000 --gid app --shell /bin/bash -d /app app
    
    RUN apt install -y mc sudo syslog-ng realmd gss-ntlmssp
    

    the build in tfs pipeline creates app docker image derived from above and adds following env variables, also copies build to /app

    RUN chmod 0700 run.sh
    ENV KRB5_KTNAME=/app/is.k01.HTTP.keytab
    ENV KRB5_TRACE=/dev/stdout
    ENV ASPNETCORE_URLS=http://*:80;https://+:443
    RUN chown app:app /app -R
    USER app
    

    the app is being run by run.sh

    service syslog-ng start
    kinit HTTP/is.k01.mydomain.com@MYDOMAIN.COM -k -t /app/is.k01.HTTP.keytab
    klist
    dotnet dev-certs https
    dotnet /app/SampleApi.dll
    

    klist lists the principal which has assigned the SPN to the machine

    in ie and firefox i have added the network.negotiate-auth.trusted-uris to my app

    however i am getting the login dialog with no success to log in

    so the question is:

    How can I enable debug log with Microsoft.AspNetCore.Authentication.Negotiate package?

    My assumption is that this package does not communicate with kerberos properly, perhaps some package is missing, not running or something.

    Also note that the container and .net app is connected successfully to the domain because I use integrated security for connection to the database which works.

    **** Edit > Answer to first part

    To enable logs, one should enable logs in kestrel: in appsettings.json:

      "Logging": {
        "LogLevel": {
          "Default": "Debug",
        }
      },
    

    In program.cs:

    Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
    {
        logging.AddFilter("Microsoft", LogLevel.Debug);
        logging.AddFilter("System", LogLevel.Debug);
        logging.ClearProviders();
        logging.AddConsole();
    })
    .ConfigureWebHostDefaults(webBuilder =>
    {
    

    In Startup.cs one can track the negotiate events:

    services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate(
    
        options =>
        {
            options.PersistKerberosCredentials = true;
            options.Events = new NegotiateEvents()
            {
                OnAuthenticated = challange =>
                {
                    ..
                },
                OnChallenge = challange =>
                {
                    ..
                },
                OnAuthenticationFailed = context =>
                {
                    // context.SkipHandler();
                    Console.WriteLine($"{DateTimeOffset.Now.ToString(czechCulture)} OnAuthenticationFailed/Scheme: {context.Scheme.Str()}, Request: {context.Request.Str()}");
                    Console.WriteLine("context?.HttpContext?.Features?.Select(f=>f.Key.Name.ToString())");
                    var items = context?.HttpContext?.Features?.Select(f => "- " + f.Key?.Name?.ToString());
                    if (items != null)
                    {
                        Console.WriteLine(string.Join("
    ", items));
                    }
                    Console.WriteLine("context.HttpContext.Features.Get<IConnectionItemsFeature>()?.Items " + context.HttpContext.Features.Get<IConnectionItemsFeature>()?.Items?.Count);
                    var items2 = context.HttpContext?.Features.Get<IConnectionItemsFeature>()?.Items?.Select(f => "- " + f.Key?.ToString() + "=" + f.Value?.ToString());
                    if (items2 != null) {
                        Console.WriteLine(string.Join("
    ", items2));
                    }
                    return Task.CompletedTask;
                }
            };
        }
    );
    

    **** Edit

    Meanwhile according my goal to allow windows authentication in .net core docker web app i was going through the source code of .net core, and corefx and trucated the auth code to this sample console app:

    try
    {
        var token = "MyToken==";
        var secAssembly = typeof(AuthenticationException).Assembly;
        Console.WriteLine("var ntAuthType = secAssembly.GetType(System.Net.NTAuthentication, throwOnError: true);");
        var ntAuthType = secAssembly.GetType("System.Net.NTAuthentication", throwOnError: true);
        Console.WriteLine("var _constructor = ntAuthType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First();");
        var _constructor = ntAuthType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First();
        Console.WriteLine("var credential = CredentialCache.DefaultCredentials;");
        var credential = CredentialCache.DefaultCredentials;
        Console.WriteLine("var _instance = _constructor.Invoke(new object[] { true, Negotiate, credential, null, 0, null });");
        var _instance = _constructor.Invoke(new object[] { true, "Negotiate", credential, null, 0, null });
    
        var negoStreamPalType = secAssembly.GetType("System.Net.Security.NegotiateStreamPal", throwOnError: true);
        var _getException = negoStreamPalType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(info => info.Name.Equals("CreateExceptionFromError")).Single();
    
    
        Console.WriteLine("var _getOutgoingBlob = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => info.Name.Equals(GetOutgoingBlob) && info.GetParameters().Count() == 3).Single();");
        var _getOutgoingBlob = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => info.Name.Equals("GetOutgoingBlob") && info.GetParameters().Count() == 3).Single();
        Console.WriteLine("var decodedIncomingBlob = Convert.FromBase64String(token);;");
        var decodedIncomingBlob = Convert.FromBase64String(token);
        Console.WriteLine("var parameters = new object[] { decodedIncomingBlob, false, null };");
        var parameters = new object[] { decodedIncomingBlob, false, null };
        Console.WriteLine("var blob = (byte[])_getOutgoingBlob.Invoke(_instance, parameters);");
        var blob = (byte[])_getOutgoingBlob.Invoke(_instance, parameters);
        if (blob != null)
        {
            Console.WriteLine("var out1 = Convert.ToBase64String(blob);");
            var out1 = Convert.ToBase64String(blob);
            Console.WriteLine(out1);
        }
        else
        {
            Console.WriteLine("null blob value returned");
    
    
            var securityStatusType = secAssembly.GetType("System.Net.SecurityStatusPal", throwOnError: true);
            var _statusException = securityStatusType.GetField("Exception");
            var securityStatus = parameters[2];
            var error = (Exception)(_statusException.GetValue(securityStatus) ?? _getException.Invoke(null, new[] { securityStatus }));
            Console.WriteLine("Error:");
            Console.WriteLine(error);
            Console.WriteLine("securityStatus:");
            Console.WriteLine(securityStatus.ToString());
        }
    }
    catch(Exception exc)
    {
        Console.WriteLine(exc.Message);
    }
    

    So i found out that the library communicates with System.Net.NTAuthentication which communicates with System.Net.Security.NegotiateStreamPal which communicates with unix version of Interop.NetSecurityNative.InitSecContext

    which should somehow trigger the GSSAPI in os

    In dotnet runtime git they tell us that gss-ntlmssp is required for this to work even that it is not mentioned anyhow in the aspnet core documentation.

    https://github.com/dotnet/runtime/issues?utf8=%E2%9C%93&q=gss-ntlmssp

    Nevertheless I have compiled the gss-ntlmssp and found out that without this library it throws error "An unsupported mechanism was requested.". With my library it throws error "No credentials were supplied, or the credentials were unavailable or inaccessible.", but never access to any gss_* methods.

    I have tested usage of gss methods by adding the log entry to file which never occured.. fe:

    OM_uint32 gss_init_sec_context(OM_uint32 *minor_status,
                                   gss_cred_id_t claimant_cred_handle,
                                   gss_ctx_id_t *context_handle,
                                   gss_name_t target_name,
                                   gss_OID mech_type,
                                   OM_uint32 req_flags,
                                   OM_uint32 time_req,
                                   gss_channel_bindings_t input_chan_bindings,
                                   gss_buffer_t input_token,
                                   gss_OID *actual_mech_type,
                                   gss_buffer_t output_token,
                                   OM_uint32 *ret_flags,
                                   OM_uint32 *time_rec)
    {
       FILE *fp;
       fp = fopen("/tmp/gss-debug.log", "w+");
       fprintf(fp, "gss_init_sec_context
    ");
       fclose(fp);
        return gssntlm_init_sec_context(minor_status,
                                        claimant_cred_handle,
                                        context_handle,
                                        target_name,
                                        mech_type,
                                        req_flags,
                                        time_req,
                                        input_chan_bindings,
                                        input_token,
                                        actual_mech_type,
                                        output_token,
                                        ret_flags,
                                        time_rec);
    }
    

    So .net calls gssapi, and gssapi does not call mechanism.

    I have observed the same behavior in centos7 vm, ubuntu windows subsystem, and debian docker image (customized mcr.microsoft.com/dotnet/core/sdk:3.1-buster)

    Kerberos Sidecar Container

    Authenticate .NET Core Client of SQL Server with Integrated Security from Linux Docker Container

  • 相关阅读:
    常用软件整理列表
    红黑树的旋转(C语言)
    Linux 内核编译
    2017年9月11日
    2017年 9月10日
    2017年9月8号 开学第一天
    开始学习.net的第二天
    前端工作需要什么
    Kubernetes容器编排技术---Kubernetes基本概念和术语(一)
    监控工具之---Prometheus探索PromQL(二)
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/13356623.html
Copyright © 2011-2022 走看看