Fix up how OIDC errors flow (#4520)
* Add regression test for #4384 * Fix up how OIDC errors flow #4384
This commit is contained in:
parent
86071c9db4
commit
d838165642
|
|
@ -73,6 +73,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.TestHo
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization", "..\Security\Authorization\Core\src\Microsoft.AspNetCore.Authorization.csproj", "{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OpenIdConnect", "..\Security\Authentication\OpenIdConnect\src\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj", "{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OAuth", "..\Security\Authentication\OAuth\src\Microsoft.AspNetCore.Authentication.OAuth.csproj", "{406DF28A-0B58-408E-96B0-2D373EE36352}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication", "..\Security\Authentication\Core\src\Microsoft.AspNetCore.Authentication.csproj", "{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -383,6 +389,42 @@ Global
|
|||
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x64.Build.0 = Release|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -418,6 +460,9 @@ Global
|
|||
{38027842-48A7-4A64-A44F-004BAF0AB450} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
|
||||
{C520D48E-87A0-463D-B4CF-3E6B68F8F4D0} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
|
||||
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
|
||||
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
|
||||
{406DF28A-0B58-408E-96B0-2D373EE36352} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
|
||||
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {81AADD49-473B-43ED-8A08-F6B7A058AA39}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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.Authorization;
|
||||
|
||||
using System.Net;
|
||||
|
|
@ -11,7 +11,9 @@ using Microsoft.AspNetCore.Authorization;
|
|||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -158,5 +160,60 @@ namespace Microsoft.AspNetCore.Authentication.AzureAD.FunctionalTests
|
|||
// Assert
|
||||
Assert.Equal(expectedStatusCode, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ADB2C_EndToEnd_PasswordReset()
|
||||
{
|
||||
var client = Factory.WithWebHostBuilder(builder => builder.ConfigureTestServices(
|
||||
services =>
|
||||
{
|
||||
services
|
||||
.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
|
||||
.AddAzureADB2C(o =>
|
||||
{
|
||||
o.Instance = "https://login.microsoftonline.com/tfp/";
|
||||
o.ClientId = "ClientId";
|
||||
o.CallbackPath = "/signin-oidc";
|
||||
o.Domain = "test.onmicrosoft.com";
|
||||
o.SignUpSignInPolicyId = "B2C_1_SiUpIn";
|
||||
o.ResetPasswordPolicyId = "B2C_1_SSPR";
|
||||
o.EditProfilePolicyId = "B2C_1_SiPe";
|
||||
});
|
||||
|
||||
services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, o =>
|
||||
{
|
||||
o.Configuration = new OpenIdConnectConfiguration()
|
||||
{
|
||||
Issuer = "https://www.example.com",
|
||||
TokenEndpoint = "https://www.example.com/token",
|
||||
AuthorizationEndpoint = "https://www.example.com/authorize",
|
||||
EndSessionEndpoint = "https://www.example.com/logout"
|
||||
};
|
||||
// CookieContainer doesn't allow cookies from other paths
|
||||
o.CorrelationCookie.Path = "/";
|
||||
o.NonceCookie.Path = "/";
|
||||
});
|
||||
|
||||
services.AddMvc(o => o.Filters.Add(
|
||||
new AuthorizeFilter(new AuthorizationPolicyBuilder(new[] { AzureADB2CDefaults.AuthenticationScheme })
|
||||
.RequireAuthenticatedUser().Build())));
|
||||
})).CreateClient(new WebApplicationFactoryClientOptions() { AllowAutoRedirect = false });
|
||||
|
||||
var response = await client.GetAsync("/api/get");
|
||||
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||
|
||||
var location = response.Headers.Location;
|
||||
Assert.StartsWith("https://www.example.com/authorize", location.AbsoluteUri);
|
||||
var queryString = location.Query;
|
||||
var query = QueryHelpers.ParseQuery(queryString);
|
||||
var state = query["state"];
|
||||
Assert.False(StringValues.IsNullOrEmpty(state));
|
||||
|
||||
// Mock Authorization response
|
||||
response = await client.GetAsync($"/signin-oidc?error=access_denied&error_description=AADB2C90118&state={state}");
|
||||
|
||||
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||
Assert.Equal("/AzureADB2C/Account/ResetPassword/AzureADB2C", response.Headers.Location.OriginalString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
|
|
@ -9,16 +9,8 @@
|
|||
<Reference Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" />
|
||||
<Reference Include="Microsoft.AspNetCore.Authorization" />
|
||||
<Reference Include="Microsoft.AspNetCore.DataProtection.Extensions" />
|
||||
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
||||
<Reference Include="Microsoft.AspNetCore" />
|
||||
<Reference Include="Microsoft.AspNetCore.Mvc" />
|
||||
<Reference Include="Microsoft.AspNetCore.Server.IISIntegration" />
|
||||
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration.CommandLine" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration.UserSecrets" />
|
||||
<Reference Include="Microsoft.Extensions.Logging.Configuration" />
|
||||
<Reference Include="Microsoft.Extensions.Logging.Console" />
|
||||
<Reference Include="Microsoft.Extensions.Logging.Debug" />
|
||||
<Reference Include="Microsoft.NET.Sdk.Razor" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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;
|
||||
|
|
@ -23,55 +23,8 @@ namespace AzureAD.WebSite
|
|||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
|
||||
{
|
||||
var builder = new WebHostBuilder()
|
||||
.UseKestrel((builderContext, options) =>
|
||||
{
|
||||
options.Configure(builderContext.Configuration.GetSection("Kestrel"));
|
||||
})
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.ConfigureAppConfiguration((hostingContext, config) =>
|
||||
{
|
||||
var env = hostingContext.HostingEnvironment;
|
||||
|
||||
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
|
||||
if (appAssembly != null)
|
||||
{
|
||||
config.AddUserSecrets(appAssembly, optional: true);
|
||||
}
|
||||
}
|
||||
|
||||
config.AddEnvironmentVariables();
|
||||
|
||||
if (args != null)
|
||||
{
|
||||
config.AddCommandLine(args);
|
||||
}
|
||||
})
|
||||
.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
logging.AddConsole();
|
||||
logging.AddDebug();
|
||||
})
|
||||
.UseIISIntegration()
|
||||
.UseDefaultServiceProvider((context, options) =>
|
||||
{
|
||||
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
|
||||
});
|
||||
|
||||
if (args != null)
|
||||
{
|
||||
builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
|
||||
}
|
||||
|
||||
builder.UseStartup<Startup>();
|
||||
|
||||
return builder;
|
||||
return WebHost.CreateDefaultBuilder()
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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;
|
||||
|
|
@ -92,5 +92,10 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
{
|
||||
return new HandleRequestResult() { Skipped = true };
|
||||
}
|
||||
|
||||
public new static HandleRequestResult NoResult()
|
||||
{
|
||||
return new HandleRequestResult() { None = true };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
return HandleRequestResult.Handle();
|
||||
}
|
||||
|
||||
return HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties);
|
||||
return HandleRequestResult.NoResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
|||
// Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information.
|
||||
if (StringValues.Equals(error, "access_denied"))
|
||||
{
|
||||
return await HandleAccessDeniedErrorAsync(properties);
|
||||
var result = await HandleAccessDeniedErrorAsync(properties);
|
||||
return !result.None ? result
|
||||
: HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties);
|
||||
}
|
||||
|
||||
var failureMessage = new StringBuilder();
|
||||
|
|
|
|||
|
|
@ -560,7 +560,11 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
// Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information.
|
||||
if (string.Equals(authorizationResponse.Error, "access_denied", StringComparison.Ordinal))
|
||||
{
|
||||
return await HandleAccessDeniedErrorAsync(properties);
|
||||
var result = await HandleAccessDeniedErrorAsync(properties);
|
||||
if (!result.None)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return HandleRequestResult.Fail(CreateOpenIdConnectProtocolException(authorizationResponse, response: null), properties);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,9 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
// approve the authorization demand requested by the remote authorization server.
|
||||
// Since it's a frequent scenario (that is not caused by incorrect configuration),
|
||||
// denied errors are handled differently using HandleAccessDeniedErrorAsync().
|
||||
return await HandleAccessDeniedErrorAsync(properties);
|
||||
var result = await HandleAccessDeniedErrorAsync(properties);
|
||||
return !result.None ? result
|
||||
: HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties);
|
||||
}
|
||||
|
||||
var returnedToken = query["oauth_token"];
|
||||
|
|
@ -311,4 +313,4 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue