Skip to content

Add new Negotiate Auth handler #9831

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
May 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8e4fc46
Proof of concept
Tratcher Apr 1, 2019
59c4b78
Misadventures in Dockerland
Tratcher Apr 2, 2019
c9fc2ce
Cleanup
Tratcher Apr 2, 2019
6ab448e
Rename to Negotiate
Tratcher Apr 19, 2019
686f0e3
Auth handler rough draft
Tratcher Apr 19, 2019
981977b
Cleanup
Tratcher Apr 19, 2019
b4e0fd3
Error handling
Tratcher Apr 19, 2019
c19c4ff
Rename Samples
Tratcher Apr 19, 2019
3891c64
Fix Samples casing
Tratcher Apr 19, 2019
1f09bc2
Test infrastructure (ignore the contents)
Tratcher Apr 23, 2019
e77e59a
Use connection features, cleanup
Tratcher Apr 23, 2019
1bf91ba
Add functional test
Tratcher Apr 23, 2019
fafd465
Unit tests
Tratcher Apr 25, 2019
18b1726
Functional tests
Tratcher Apr 26, 2019
36c1f29
Reorganize. Implement events.
Tratcher Apr 29, 2019
d19126f
Ref assemblies
Tratcher Apr 29, 2019
431bdf0
Self review, remove docker
Tratcher Apr 29, 2019
acabd0c
Hard fail for ANCM out-of-proc.
Tratcher Apr 29, 2019
f91bca5
Switch to IConnectionCompleteFeature
Tratcher May 1, 2019
b360f95
Clean up constants, challenges
Tratcher May 1, 2019
f2fb1af
Code cleanup
Tratcher May 1, 2019
db8a259
Better tests
Tratcher May 3, 2019
817acdf
Code cleanup
Tratcher May 3, 2019
8321037
React to corefx http2 change
Tratcher May 4, 2019
6a3144a
Make connection persistence configurable
Tratcher May 8, 2019
e6e85d7
Avoid re-execute errors
Tratcher May 8, 2019
3d20730
Protocal spelling
Tratcher May 8, 2019
041b2f4
Ref assemblies
Tratcher May 8, 2019
bbdc3bc
Code cleanup
Tratcher May 9, 2019
5726e87
Add cross machine test infrastructure
Tratcher May 10, 2019
fa04f5c
Test fixup
May 13, 2019
0ea8227
Multi-stage kerberos
Tratcher May 13, 2019
4eee552
Skip cross machine tests
Tratcher May 13, 2019
b80b980
Too much $
Tratcher May 13, 2019
44775d1
Logging
Tratcher May 14, 2019
5aa62db
CrossMachine readme
Tratcher May 14, 2019
2fd709e
Event tests
Tratcher May 14, 2019
d6b38cc
Use AuthZ middleware
Tratcher May 14, 2019
c6f10cf
Review cleanup
Tratcher May 14, 2019
40091e9
Move test assets
Tratcher May 15, 2019
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
1 change: 1 addition & 0 deletions eng/ProjectReferences.props
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Google" ProjectPath="$(RepoRoot)src\Security\Authentication\Google\src\Microsoft.AspNetCore.Authentication.Google.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Google\ref\Microsoft.AspNetCore.Authentication.Google.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.JwtBearer" ProjectPath="$(RepoRoot)src\Security\Authentication\JwtBearer\src\Microsoft.AspNetCore.Authentication.JwtBearer.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\JwtBearer\ref\Microsoft.AspNetCore.Authentication.JwtBearer.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" ProjectPath="$(RepoRoot)src\Security\Authentication\MicrosoftAccount\src\Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\MicrosoftAccount\ref\Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Negotiate" ProjectPath="$(RepoRoot)src\Security\Authentication\Negotiate\src\Microsoft.AspNetCore.Authentication.Negotiate.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Negotiate\ref\Microsoft.AspNetCore.Authentication.Negotiate.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.OAuth" ProjectPath="$(RepoRoot)src\Security\Authentication\OAuth\src\Microsoft.AspNetCore.Authentication.OAuth.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\OAuth\ref\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" ProjectPath="$(RepoRoot)src\Security\Authentication\OpenIdConnect\src\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\OpenIdConnect\ref\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Twitter" ProjectPath="$(RepoRoot)src\Security\Authentication\Twitter\src\Microsoft.AspNetCore.Authentication.Twitter.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Twitter\ref\Microsoft.AspNetCore.Authentication.Twitter.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.AspNetCore.Authentication.Negotiate.netcoreapp3.0.cs" />
<Reference Include="Microsoft.AspNetCore.Authentication" />
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.AspNetCore.Authentication.Negotiate
{
public partial class AuthenticatedContext : Microsoft.AspNetCore.Authentication.ResultContext<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions>
{
public AuthenticatedContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions options) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions)) { }
}
public partial class AuthenticationFailedContext : Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions>
{
public AuthenticationFailedContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions options) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions), default(Microsoft.AspNetCore.Authentication.AuthenticationProperties)) { }
public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
public partial class ChallengeContext : Microsoft.AspNetCore.Authentication.PropertiesContext<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions>
{
public ChallengeContext(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme, Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions options, Microsoft.AspNetCore.Authentication.AuthenticationProperties properties) : base (default(Microsoft.AspNetCore.Http.HttpContext), default(Microsoft.AspNetCore.Authentication.AuthenticationScheme), default(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions), default(Microsoft.AspNetCore.Authentication.AuthenticationProperties)) { }
public bool Handled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public void HandleResponse() { }
}
public static partial class NegotiateDefaults
{
public const string AuthenticationScheme = "Negotiate";
}
public partial class NegotiateEvents
{
public NegotiateEvents() { }
public System.Func<Microsoft.AspNetCore.Authentication.Negotiate.AuthenticatedContext, System.Threading.Tasks.Task> OnAuthenticated { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Func<Microsoft.AspNetCore.Authentication.Negotiate.AuthenticationFailedContext, System.Threading.Tasks.Task> OnAuthenticationFailed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Func<Microsoft.AspNetCore.Authentication.Negotiate.ChallengeContext, System.Threading.Tasks.Task> OnChallenge { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public virtual System.Threading.Tasks.Task Authenticated(Microsoft.AspNetCore.Authentication.Negotiate.AuthenticatedContext context) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticationFailed(Microsoft.AspNetCore.Authentication.Negotiate.AuthenticationFailedContext context) { throw null; }
public virtual System.Threading.Tasks.Task Challenge(Microsoft.AspNetCore.Authentication.Negotiate.ChallengeContext context) { throw null; }
}
public partial class NegotiateHandler : Microsoft.AspNetCore.Authentication.AuthenticationHandler<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions>, Microsoft.AspNetCore.Authentication.IAuthenticationHandler, Microsoft.AspNetCore.Authentication.IAuthenticationRequestHandler
{
public NegotiateHandler(Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions> options, Microsoft.Extensions.Logging.ILoggerFactory logger, System.Text.Encodings.Web.UrlEncoder encoder, Microsoft.AspNetCore.Authentication.ISystemClock clock) : base (default(Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions>), default(Microsoft.Extensions.Logging.ILoggerFactory), default(System.Text.Encodings.Web.UrlEncoder), default(Microsoft.AspNetCore.Authentication.ISystemClock)) { }
protected new Microsoft.AspNetCore.Authentication.Negotiate.NegotiateEvents Events { get { throw null; } set { } }
protected override System.Threading.Tasks.Task<object> CreateEventsAsync() { throw null; }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticateResult> HandleAuthenticateAsync() { throw null; }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override System.Threading.Tasks.Task HandleChallengeAsync(Microsoft.AspNetCore.Authentication.AuthenticationProperties properties) { throw null; }
[System.Diagnostics.DebuggerStepThroughAttribute]
public System.Threading.Tasks.Task<bool> HandleRequestAsync() { throw null; }
}
public partial class NegotiateOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions
{
public NegotiateOptions() { }
public new Microsoft.AspNetCore.Authentication.Negotiate.NegotiateEvents Events { get { throw null; } set { } }
public bool PersistKerberosCredentials { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool PersistNtlmCredentials { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
}
namespace Microsoft.Extensions.DependencyInjection
{
public static partial class NegotiateExtensions
{
public static Microsoft.AspNetCore.Authentication.AuthenticationBuilder AddNegotiate(this Microsoft.AspNetCore.Authentication.AuthenticationBuilder builder) { throw null; }
public static Microsoft.AspNetCore.Authentication.AuthenticationBuilder AddNegotiate(this Microsoft.AspNetCore.Authentication.AuthenticationBuilder builder, System.Action<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions> configureOptions) { throw null; }
public static Microsoft.AspNetCore.Authentication.AuthenticationBuilder AddNegotiate(this Microsoft.AspNetCore.Authentication.AuthenticationBuilder builder, string authenticationScheme, System.Action<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions> configureOptions) { throw null; }
public static Microsoft.AspNetCore.Authentication.AuthenticationBuilder AddNegotiate(this Microsoft.AspNetCore.Authentication.AuthenticationBuilder builder, string authenticationScheme, string displayName, System.Action<Microsoft.AspNetCore.Authentication.Negotiate.NegotiateOptions> configureOptions) { throw null; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>

<ItemGroup>
<Reference Include="Microsoft.AspNetCore" />
<Reference Include="Microsoft.AspNetCore.Authentication.Negotiate" />
<Reference Include="Microsoft.AspNetCore.Authorization" />
<Reference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace NegotiateAuthSample
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:6449",
"sslPort": 44369
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"NegotiateAuthSample": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Negotiate;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace NegotiateAuthSample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseAuthentication();
app.UseAuthorization();
app.Run(HandleRequest);
}

public async Task HandleRequest(HttpContext context)
{
var user = context.User.Identity;
await context.Response.WriteAsync($"Authenticated? {user.IsAuthenticated}, Name: {user.Name}, Protocol: {context.Request.Protocol}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information",
"Microsoft.AspNetCore.Authentication": "Debug"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Authentication.Negotiate
{
/// <summary>
/// State for the Authenticated event.
/// </summary>
public class AuthenticatedContext : ResultContext<NegotiateOptions>
{
/// <summary>
/// Creates a new <see cref="AuthenticatedContext"/>.
/// </summary>
/// <param name="context"></param>
/// <param name="scheme"></param>
/// <param name="options"></param>
public AuthenticatedContext(
HttpContext context,
AuthenticationScheme scheme,
NegotiateOptions options)
: base(context, scheme, options) { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Authentication.Negotiate
{
/// <summary>
/// State for the AuthenticationFailed event.
/// </summary>
public class AuthenticationFailedContext : RemoteAuthenticationContext<NegotiateOptions>
{
/// <summary>
/// Creates a <see cref="AuthenticationFailedContext"/>.
/// </summary>
/// <param name="context"></param>
/// <param name="scheme"></param>
/// <param name="options"></param>
public AuthenticationFailedContext(
HttpContext context,
AuthenticationScheme scheme,
NegotiateOptions options)
: base(context, scheme, options, properties: null) { }

/// <summary>
/// The exception that occured while processing the authentication.
/// </summary>
public Exception Exception { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Authentication.Negotiate
{
/// <summary>
/// State for the Challenge event.
/// </summary>
public class ChallengeContext : PropertiesContext<NegotiateOptions>
{
/// <summary>
/// Creates a new <see cref="ChallengeContext"/>.
/// </summary>
/// <param name="context"></param>
/// <param name="scheme"></param>
/// <param name="options"></param>
/// <param name="properties"></param>
public ChallengeContext(
HttpContext context,
AuthenticationScheme scheme,
NegotiateOptions options,
AuthenticationProperties properties)
: base(context, scheme, options, properties) { }

/// <summary>
/// If true, will skip any default logic for this challenge.
/// </summary>
public bool Handled { get; private set; }

/// <summary>
/// Skips any default logic for this challenge.
/// </summary>
public void HandleResponse() => Handled = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;

namespace Microsoft.AspNetCore.Authentication.Negotiate
{
/// <summary>
/// Specifies events which the <see cref="NegotiateHandler"/> invokes to enable developer control over the authentication process.
/// </summary>
public class NegotiateEvents
{
/// <summary>
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.
/// </summary>
public Func<AuthenticationFailedContext, Task> OnAuthenticationFailed { get; set; } = context => Task.CompletedTask;

/// <summary>
/// Invoked after the authentication is complete and a ClaimsIdentity has been generated.
/// </summary>
public Func<AuthenticatedContext, Task> OnAuthenticated { get; set; } = context => Task.CompletedTask;

/// <summary>
/// Invoked before a challenge is sent back to the caller.
/// </summary>
public Func<ChallengeContext, Task> OnChallenge { get; set; } = context => Task.CompletedTask;

/// <summary>
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.
/// </summary>
public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context);

/// <summary>
/// Invoked after the authentication is complete and a ClaimsIdentity has been generated.
/// </summary>
public virtual Task Authenticated(AuthenticatedContext context) => OnAuthenticated(context);

/// <summary>
/// Invoked before a challenge is sent back to the caller.
/// </summary>
public virtual Task Challenge(ChallengeContext context) => OnChallenge(context);
}
}
Loading