Skip to content

Determine If I have Delegatable Credentials in my ASPX Web Site

Malcolm Stewart edited this page Dec 28, 2020 · 1 revision

Determine If I have Delegatable Credentials in my ASPX Web Site

The nice thing about ASPX-based web sites is that you can add an in-line scripted page to the site and it will compile the next time the App Pool is restarted and become part of the application. This can work for your own web site, but it can also work for other sites that are ASPX-based. This will probably also work for ASMX-based SOAP service sites but probably not for MVC-based web sites.

The Technique

  1. Copy the scripted page below into Notepad and save as DiagInfo.aspx.
  2. In Windows Explorer, locate the folder in the web site that contains the web.config file. It should have at least one other ASPX page in it.
  3. Copy DiagInfo.aspx into that folder.
    DiagInfo.aspx placement
  4. Restart the App Pool. Running IISRESET from an Admin command-prompt also works.
  5. Browse to your web site's URL and add DiagInfo.aspx to the end, e.g., https://con2016/Test/DiagInfo.aspx

How to Tell Whether You Can Impersonate or Delegate Credentials

When browsing from a client other than the IIS machine, the DiagInfo.aspx page should identify your user account in three different entries and show you are using Kerberos credentials and that they are delegatable.

Delegatable credentials

Even if Kerberos is configured correctly, browsing from the web server will show Impersonation only:

Local browser

A Note about IIS SPNs

Unlike with SQL Server, the browser does not append the DNS suffix onto the host name in the URL. A web site might also have different host header names. That means you may have to add extra SPNs to the App Pool account that match what users typically type into the browser. If the App Pool accounts are local, then the existing HOSTS SPNs should be sufficient, but if they are domain accounts or the app pool uses host headers, you should create HTTP SPNs.

Note: Using the IP address instead of the host name will prevent Kerberos.

The following article has more about IIS SPNs:

https://support.microsoft.com/en-us/help/929650/how-to-use-spns-when-you-configure-web-applications-that-are-hosted-on

DiagInfo.aspx

<%@ Page Language="C#" validateRequest="false" trace="false" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
	<HEAD>
		<title>ASP.NET Diagnostic Information</title>
	</HEAD>

<script runat="server">
    private void Page_Load(object sender, System.EventArgs e)
    {
        IDictionary env = Environment.GetEnvironmentVariables();
        txtStatus.Text = "";
        LogStatus("Machine Name:        " + Environment.MachineName);
        LogStatus("Current Directory:   " + Environment.CurrentDirectory);
        LogStatus("OS Version:          " + Environment.OSVersion.Version.ToString());
        LogStatus(".NET Version:        " + Environment.Version.ToString());
        LogStatus("REMOTE_HOST:PORT:    " + this.Request.ServerVariables.Get("REMOTE_HOST") + ":" + this.Request.ServerVariables.Get("REMOTE_PORT"));
        LogStatus("LOCAL_ADDR:          " + this.Request.ServerVariables.Get("LOCAL_ADDR").ToString());
        LogStatus("SERVER_NAME:         " + this.Request.ServerVariables.Get("SERVER_NAME"));
        LogStatus("HTTPS:               " + this.Request.ServerVariables.Get("HTTPS"));
        LogStatus("HTTP_REFERER:        " + this.Request.ServerVariables.Get("HTTP_REFERER"));
        LogStatus("URL:                 " + this.Request.ServerVariables.Get("URL"));
        LogStatus("QUERY_STRING:        " + this.Request.ServerVariables.Get("QUERY_STRING"));
        LogStatus("Running as user:     " + Environment.UserDomainName + @"\" + Environment.UserName);
        LogStatus("Browser User:        " + this.User.Identity.Name);
        LogStatus("Authentication Type: " + this.User.Identity.AuthenticationType + " (" + (this.User.Identity.IsAuthenticated ? "Authenticated" : "Not authenticated") + ")");
        System.Security.Principal.WindowsIdentity w = System.Security.Principal.WindowsIdentity.GetCurrent();
        LogStatus("Name:                " + w.Name);
        LogStatus("Groups:              " + w.Groups.Count.ToString());
        LogStatus("IsAnonymous:         " + w.IsAnonymous.ToString());
        LogStatus("IsAuthenticated:     " + w.IsAuthenticated.ToString());
        LogStatus("IsGuest:             " + w.IsGuest.ToString());
        LogStatus("IsSystem:            " + w.IsSystem.ToString());
        LogStatus("Auth type:           " + w.AuthenticationType);
        LogStatus("Impersonation Level: " + w.ImpersonationLevel.ToString());
        switch (w.ImpersonationLevel.ToString())
        {
            case "Anonymous":
                {
                    LogStatus("The server process cannot obtain identification information about the client, and it cannot impersonate the client.");
                    break;
                }
            case "Delegation":
                {
                    LogStatus("The server process can impersonate the client's security context on remote systems.");
                    break;
                }
            case "Identification":
                {
                    LogStatus("The server process can obtain information about the client, such as security identifiers and privileges, but it cannot impersonate the client. This is useful for servers that export their own objects, for example, database products that export tables and views. Using the retrieved client-security information, the server can make access-validation decisions without being able to use other services that are using the client's security context.");
                    break;
                }
            case "Impersonation":
                {
                    LogStatus("The server process can impersonate the client's security context on its local system. The server cannot impersonate the client on remote systems.");
                    break;
                }
            case "None":
                {
                    LogStatus("An impersonation level is not assigned.");
                    break;
                }
        }
        LogStatus("Environment----(below)-------");
        foreach (System.Collections.DictionaryEntry a in env)
        {
            LogStatus(a.Key + "=" + a.Value);
        }
    }

    private void LogStatus(string Message)
    {
        if (txtStatus.Text.Length == 0)
        {
            txtStatus.Text = Message;
        }
        else
        {
            txtStatus.Text += "\r\n" + Message;
        }
    }
</script>

	<body>
		<form id="Form1" method="post" runat="server">
			<asp:label id="Label1" style="Z-INDEX: 101; LEFT: 16px; POSITION: absolute; TOP: 8px; width: 408px;" runat="server" Font-Bold="True" Font-Size="Large" Height="48px">ASP.NET Diagnostic Information</asp:label>
			<asp:label id="Label5" style="Z-INDEX: 104; LEFT: 16px; POSITION: absolute; TOP: 72px" runat="server" Width="88px">Environment</asp:label>
			<asp:textbox id="txtStatus" style="Z-INDEX: 102; LEFT: 176px; POSITION: absolute; TOP: 72px; height: 442px;" runat="server" Width="616px" Font-Names="Courier" TextMode="MultiLine" EnableViewState="False"></asp:textbox>
		</form>
	</body>
</HTML>
Clone this wiki locally