Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Microsoft.AspNetCore.SystemWebAdapters.sln
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.System
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SystemWebAdapters.Apis.Tests", "test\Microsoft.AspNetCore.SystemWebAdapters.Apis.Tests\Microsoft.AspNetCore.SystemWebAdapters.Apis.Tests.csproj", "{E4D9A131-DC4E-403F-A10F-65F5E5E42475}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsAuth", "samples\WindowsAuth\WindowsAuth.csproj", "{B5E840F8-2021-4175-BFBF-F9447506242E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -222,6 +224,10 @@ Global
{E4D9A131-DC4E-403F-A10F-65F5E5E42475}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4D9A131-DC4E-403F-A10F-65F5E5E42475}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4D9A131-DC4E-403F-A10F-65F5E5E42475}.Release|Any CPU.Build.0 = Release|Any CPU
{B5E840F8-2021-4175-BFBF-F9447506242E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5E840F8-2021-4175-BFBF-F9447506242E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5E840F8-2021-4175-BFBF-F9447506242E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5E840F8-2021-4175-BFBF-F9447506242E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -264,6 +270,7 @@ Global
{FA39AC22-0725-4532-A682-B054ADA5BDA2} = {03E4CEAB-D845-402A-9311-F7390B24BA2A}
{17055F45-E79A-41EF-825E-0B2211433729} = {A1BDA50C-D70B-416C-97F1-74B0649797C5}
{E4D9A131-DC4E-403F-A10F-65F5E5E42475} = {A1BDA50C-D70B-416C-97F1-74B0649797C5}
{B5E840F8-2021-4175-BFBF-F9447506242E} = {95915611-30BF-4AFF-AE41-5CDC6F57DCF7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DABA3C65-9D74-4EB6-9B1C-730328710EAD}
Expand Down
23 changes: 23 additions & 0 deletions samples/WindowsAuth/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Authentication.Negotiate;
using Microsoft.AspNetCore.SystemWebAdapters;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();

var app = builder.Build();

app.UseAuthentication();

app.MapGet("/", (HttpContext context) =>
{
return new
{
User = context.User.Identity?.Name,
Principal = context.AsSystemWeb().User.Identity?.Name,
LogonUser = OperatingSystem.IsWindows() ? context.AsSystemWeb().Request.LogonUserIdentity?.Name : null,
};
});

app.Run();
38 changes: 38 additions & 0 deletions samples/WindowsAuth/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": false,
"iisExpress": {
"applicationUrl": "http://localhost:50790",
"sslPort": 44383
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5041",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7245;http://localhost:5041",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
18 changes: 18 additions & 0 deletions samples/WindowsAuth/WindowsAuth.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="8.0.7" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SystemWebAdapters.CoreServices\Microsoft.AspNetCore.SystemWebAdapters.CoreServices.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SystemWebAdapters\Microsoft.AspNetCore.SystemWebAdapters.csproj" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions samples/WindowsAuth/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions samples/WindowsAuth/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,29 @@

using Microsoft.AspNetCore.Http.Features.Authentication;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Claims;
using System.Security.Principal;
using System.Web;

namespace Microsoft.AspNetCore.SystemWebAdapters.Features;

/// <summary>
/// Represents the user as an <see cref="IPrincipal"/> as opposed to the in-built <see cref="IHttpAuthenticationFeature.User"/> which
/// expects a <see cref="ClaimsPrincipal"/>.
/// Represents the users that ASP.NET Framework used.
/// </summary>
[Experimental(Constants.ExperimentalFeatures.DiagnosticId)]
public interface IPrincipalUserFeature
public interface IRequestUserFeature
{
/// <summary>
/// Gets or sets the user that corresponds to <see cref="HttpContext.User" />
/// </summary>
IPrincipal? User { get; set; }

/// <summary>
/// Gets the logged on user that corresponds to <see cref="HttpRequest.LogonUserIdentity" />
/// </summary>
WindowsIdentity? LogonUserIdentity { get; }
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ internal HttpRequest() { }
public bool IsLocal { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public bool IsSecureConnection { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public string this[string key] { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public System.Security.Principal.WindowsIdentity LogonUserIdentity { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public System.Collections.Specialized.NameValueCollection Params { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public string Path { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public string PathInfo { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
Expand Down Expand Up @@ -483,6 +484,7 @@ public abstract partial class HttpRequestBase
public virtual bool IsLocal { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public virtual bool IsSecureConnection { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public virtual string this[string key] { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public virtual System.Security.Principal.WindowsIdentity LogonUserIdentity { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public virtual System.Collections.Specialized.NameValueCollection Params { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public virtual string Path { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public virtual string PathInfo { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
Expand Down Expand Up @@ -527,6 +529,7 @@ public partial class HttpRequestWrapper : System.Web.HttpRequestBase
public override bool IsLocal { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public override bool IsSecureConnection { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public override string this[string key] { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public override System.Security.Principal.WindowsIdentity LogonUserIdentity { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public override System.Collections.Specialized.NameValueCollection Params { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public override string Path { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public override string PathInfo { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
Expand Down
17 changes: 2 additions & 15 deletions src/Microsoft.AspNetCore.SystemWebAdapters/HttpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,21 +99,8 @@ public IHttpHandler? Handler

public IPrincipal User
{
get => Context.Features.Get<IPrincipalUserFeature>()?.User ?? Context.User;
set
{
if (Context.Features.Get<IPrincipalUserFeature>() is { } feature)
{
feature.User = value;
}
else
{
var newFeature = new PrincipalUserFeature(Context) { User = value };

Context.Features.Set<IPrincipalUserFeature>(newFeature);
Context.Features.Set<IHttpAuthenticationFeature>(newFeature);
}
}
get => Context.Features.Get<IRequestUserFeature>()?.User ?? Context.User;
set => Context.GetRequestUser().User = value;
}

public HttpSessionState? Session => Context.Features.Get<ISessionStateFeature>()?.Session;
Expand Down
2 changes: 2 additions & 0 deletions src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ internal HttpRequest(HttpRequestCore request)

public string CurrentExecutionFilePath => Request.HttpContext.Features.GetRequired<IHttpRequestPathFeature>().CurrentExecutionFilePath;

public WindowsIdentity? LogonUserIdentity => Request.HttpContext.GetRequestUser().LogonUserIdentity;

public NameValueCollection Headers => _headers ??= Request.Headers.ToNameValueCollection();

public Uri Url => new(Request.GetEncodedUrl());
Expand Down
2 changes: 2 additions & 0 deletions src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public abstract class HttpRequestBase

public virtual string? FilePath => throw new NotImplementedException();

public virtual WindowsIdentity? LogonUserIdentity => throw new NotImplementedException();

public virtual ReadEntityBodyMode ReadEntityBodyMode => throw new NotImplementedException();

public virtual void SaveAs(string filename, bool includeHeaders) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Specialized;
using System.IO;
using System.Security.Principal;
using System.Text;

namespace System.Web
Expand Down Expand Up @@ -42,6 +43,8 @@ public override string? ContentType

public override NameValueCollection Form => _request.Form;

public override WindowsIdentity? LogonUserIdentity => _request.LogonUserIdentity;

public override string HttpMethod => _request.HttpMethod;

public override Stream InputStream => _request.InputStream;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Security.Claims;
using System.Security.Principal;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.SystemWebAdapters.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

namespace Microsoft.AspNetCore.SystemWebAdapters;

internal static partial class RequestUserExtensions
{
public static IRequestUserFeature GetRequestUser(this HttpContextCore context)
{
if (context.Features.Get<IRequestUserFeature>() is { } existing)
{
return existing;
}

var newFeature = new RequestUserFeature(context) { User = context.User };

context.Features.Set<IRequestUserFeature>(newFeature);
context.Features.Set<IHttpAuthenticationFeature>(newFeature);

return newFeature;
}

private sealed partial class RequestUserFeature : IRequestUserFeature, IHttpAuthenticationFeature
{
private readonly ILogger _logger;

public RequestUserFeature(HttpContextCore context)
{
var logger = (ILogger?)context.RequestServices?.GetService<ILoggerFactory>()?.CreateLogger<RequestUserFeature>();

_logger = logger ?? NullLogger.Instance;

User = context.User;
}

[LoggerMessage(0, LogLevel.Debug, "A custom principal {PrincipalType} is being used and should be replaced with a ClaimsPrincipal derived type.")]
private partial void LogNonClaimsPrincipal(Type principalType);

public IPrincipal? User { get; set; }

WindowsIdentity? IRequestUserFeature.LogonUserIdentity => User?.Identity as WindowsIdentity;

ClaimsPrincipal? IHttpAuthenticationFeature.User
{
get => GetOrCreateClaims(User);
set => User = value;
}

private ClaimsPrincipal? GetOrCreateClaims(IPrincipal? principal)
{
if (principal is null)
{
return null;
}

if (principal is ClaimsPrincipal claimsPrincipal)
{
return claimsPrincipal;
}

LogNonClaimsPrincipal(principal.GetType());

return new ClaimsPrincipal(principal);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
<Compile Include="Adapters/SessionState/ISessionState.cs" />
<Compile Include="IHtmlString.cs" />
<Compile Include="HtmlString.cs" />

<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
Expand Down
Loading