diff --git a/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs b/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs index 16b36948af..41b93ac083 100644 --- a/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs +++ b/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Web; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; @@ -272,7 +273,7 @@ namespace Microsoft.AspNetCore.Hosting { if (NameValueHeaderValue.TryParse(item, out var baggageItem)) { - activity.AddBaggage(baggageItem.Name.ToString(), baggageItem.Value.ToString()); + activity.AddBaggage(baggageItem.Name.ToString(), HttpUtility.UrlDecode(baggageItem.Value.ToString())); } } } diff --git a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs index 385424fa67..341c7c6fa4 100644 --- a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs +++ b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs @@ -345,6 +345,35 @@ namespace Microsoft.AspNetCore.Hosting.Tests Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key2" && pair.Value == "value2"); } + [Fact] + public void ActivityBaggageValuesAreUrlDecodedFromHeaders() + { + var diagnosticListener = new DiagnosticListener("DummySource"); + var hostingApplication = CreateApplication(out var features, diagnosticListener: diagnosticListener); + + diagnosticListener.Subscribe(new CallbackDiagnosticListener(pair => { }), + s => + { + if (s.StartsWith("Microsoft.AspNetCore.Hosting.HttpRequestIn")) + { + return true; + } + return false; + }); + + features.Set(new HttpRequestFeature() + { + Headers = new HeaderDictionary() + { + {"Request-Id", "ParentId1"}, + {"Correlation-Context", "Key1=value1%2F1"} + } + }); + hostingApplication.CreateContext(features); + Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName); + Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key1" && pair.Value == "value1/1"); + } + [Fact] public void ActivityTraceParentAndTraceStateFromHeaders() diff --git a/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netcoreapp.cs b/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netcoreapp.cs index 13979d60ae..fa44115139 100644 --- a/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netcoreapp.cs +++ b/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netcoreapp.cs @@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.Identity public partial class ClaimsIdentityOptions { public ClaimsIdentityOptions() { } + public string EmailClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public string RoleClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public string SecurityStampClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public string UserIdClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } diff --git a/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netstandard2.0.cs b/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netstandard2.0.cs index 13979d60ae..fa44115139 100644 --- a/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netstandard2.0.cs +++ b/src/Identity/Extensions.Core/ref/Microsoft.Extensions.Identity.Core.netstandard2.0.cs @@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.Identity public partial class ClaimsIdentityOptions { public ClaimsIdentityOptions() { } + public string EmailClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public string RoleClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public string SecurityStampClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public string UserIdClaimType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } diff --git a/src/Identity/Extensions.Core/src/ClaimsIdentityOptions.cs b/src/Identity/Extensions.Core/src/ClaimsIdentityOptions.cs index 54ba1ae069..17f383ab33 100644 --- a/src/Identity/Extensions.Core/src/ClaimsIdentityOptions.cs +++ b/src/Identity/Extensions.Core/src/ClaimsIdentityOptions.cs @@ -25,9 +25,14 @@ namespace Microsoft.AspNetCore.Identity /// public string UserIdClaimType { get; set; } = ClaimTypes.NameIdentifier; + /// + /// Gets or sets the ClaimType used for the user email claim. Defaults to . + /// + public string EmailClaimType { get; set; } = ClaimTypes.Email; + /// /// Gets or sets the ClaimType used for the security stamp claim. Defaults to "AspNet.Identity.SecurityStamp". /// public string SecurityStampClaimType { get; set; } = "AspNet.Identity.SecurityStamp"; } -} \ No newline at end of file +} diff --git a/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs b/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs index dd7e316423..859e78ad57 100644 --- a/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs +++ b/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs @@ -81,6 +81,14 @@ namespace Microsoft.AspNetCore.Identity Options.ClaimsIdentity.RoleClaimType); id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId)); id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName)); + if (UserManager.SupportsUserEmail) + { + var email = await UserManager.GetEmailAsync(user); + if (!string.IsNullOrEmpty(email)) + { + id.AddClaim(new Claim(Options.ClaimsIdentity.EmailClaimType, email)); + } + } if (UserManager.SupportsUserSecurityStamp) { id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType, @@ -154,4 +162,4 @@ namespace Microsoft.AspNetCore.Identity return id; } } -} \ No newline at end of file +} diff --git a/src/Identity/test/Identity.Test/UserClaimsPrincipalFactoryTest.cs b/src/Identity/test/Identity.Test/UserClaimsPrincipalFactoryTest.cs index befed38dd9..bcf42f459d 100644 --- a/src/Identity/test/Identity.Test/UserClaimsPrincipalFactoryTest.cs +++ b/src/Identity/test/Identity.Test/UserClaimsPrincipalFactoryTest.cs @@ -30,22 +30,33 @@ namespace Microsoft.AspNetCore.Identity.Test } [Theory] - [InlineData(false, false, false)] - [InlineData(false, true, false)] - [InlineData(true, false, false)] - [InlineData(true, true, false)] - [InlineData(true, false, true)] - [InlineData(true, true, true)] - public async Task EnsureClaimsIdentityHasExpectedClaims(bool supportRoles, bool supportClaims, bool supportRoleClaims) + [InlineData(true, false, false, false)] + [InlineData(true, true, false, false)] + [InlineData(true, false, true, false)] + [InlineData(true, true, true, false)] + [InlineData(false, false, false, true)] + [InlineData(false, true, false, true)] + [InlineData(false, false, false, false)] + [InlineData(false, true, false, false)] + [InlineData(true, false, false, true)] + [InlineData(true, true, false, true)] + [InlineData(true, false, true, true)] + [InlineData(true, true, true, true)] + public async Task EnsureClaimsIdentityHasExpectedClaims(bool supportRoles, bool supportClaims, bool supportRoleClaims, bool supportsUserEmail) { // Setup var userManager = MockHelpers.MockUserManager(); var roleManager = MockHelpers.MockRoleManager(); - var user = new PocoUser { UserName = "Foo" }; + var user = new PocoUser { UserName = "Foo", Email = "foo@bar.com" }; userManager.Setup(m => m.SupportsUserClaim).Returns(supportClaims); userManager.Setup(m => m.SupportsUserRole).Returns(supportRoles); + userManager.Setup(m => m.SupportsUserEmail).Returns(supportsUserEmail); userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); + if (supportsUserEmail) + { + userManager.Setup(m => m.GetEmailAsync(user)).ReturnsAsync(user.Email); + } var roleClaims = new[] { "Admin", "Local" }; if (supportRoles) { @@ -90,6 +101,7 @@ namespace Microsoft.AspNetCore.Identity.Test Assert.Contains( claims, c => c.Type == manager.Options.ClaimsIdentity.UserNameClaimType && c.Value == user.UserName); Assert.Contains(claims, c => c.Type == manager.Options.ClaimsIdentity.UserIdClaimType && c.Value == user.Id); + Assert.Equal(supportsUserEmail, claims.Any(c => c.Type == manager.Options.ClaimsIdentity.EmailClaimType && c.Value == user.Email)); Assert.Equal(supportRoles, claims.Any(c => c.Type == manager.Options.ClaimsIdentity.RoleClaimType && c.Value == "Admin")); Assert.Equal(supportRoles, claims.Any(c => c.Type == manager.Options.ClaimsIdentity.RoleClaimType && c.Value == "Local")); foreach (var cl in userClaims) diff --git a/src/Middleware/ResponseCaching/src/ResponseCachingExtensions.cs b/src/Middleware/ResponseCaching/src/ResponseCachingExtensions.cs index 45d905cea6..8dff8eb2f5 100644 --- a/src/Middleware/ResponseCaching/src/ResponseCachingExtensions.cs +++ b/src/Middleware/ResponseCaching/src/ResponseCachingExtensions.cs @@ -6,8 +6,15 @@ using Microsoft.AspNetCore.ResponseCaching; namespace Microsoft.AspNetCore.Builder { + /// + /// Extension methods for adding the to an application. + /// public static class ResponseCachingExtensions { + /// + /// Adds the for caching HTTP responses. + /// + /// The . public static IApplicationBuilder UseResponseCaching(this IApplicationBuilder app) { if (app == null) diff --git a/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs b/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs index b74d3f47cd..dd75fece9f 100644 --- a/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs +++ b/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs @@ -14,6 +14,9 @@ using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.ResponseCaching { + /// + /// Enable HTTP response caching. + /// public class ResponseCachingMiddleware { private static readonly TimeSpan DefaultExpirationTimeSpan = TimeSpan.FromSeconds(10); @@ -29,6 +32,13 @@ namespace Microsoft.AspNetCore.ResponseCaching private readonly IResponseCache _cache; private readonly IResponseCachingKeyProvider _keyProvider; + /// + /// Creates a new . + /// + /// The representing the next middleware in the pipeline. + /// The options for this middleware. + /// The used for logging. + /// The used for creating instances. public ResponseCachingMiddleware( RequestDelegate next, IOptions options, @@ -88,6 +98,11 @@ namespace Microsoft.AspNetCore.ResponseCaching _keyProvider = keyProvider; } + /// + /// Invokes the logic of the middleware. + /// + /// The . + /// A that completes when the middleware has completed processing. public async Task Invoke(HttpContext httpContext) { var context = new ResponseCachingContext(httpContext, _logger); diff --git a/src/SignalR/clients/java/signalr/signalr.client.java.Tests.javaproj b/src/SignalR/clients/java/signalr/signalr.client.java.Tests.javaproj index f7f91926db..251681f130 100644 --- a/src/SignalR/clients/java/signalr/signalr.client.java.Tests.javaproj +++ b/src/SignalR/clients/java/signalr/signalr.client.java.Tests.javaproj @@ -2,7 +2,11 @@ - true + + + java:signalr + + true true diff --git a/src/Tools/dotnet-user-secrets/src/Internal/InitCommand.cs b/src/Tools/dotnet-user-secrets/src/Internal/InitCommand.cs index e54f04ff7c..5b8b038596 100644 --- a/src/Tools/dotnet-user-secrets/src/Internal/InitCommand.cs +++ b/src/Tools/dotnet-user-secrets/src/Internal/InitCommand.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Linq; +using System.Xml; using System.Xml.Linq; using System.Xml.XPath; using Microsoft.Extensions.CommandLineUtils; @@ -122,7 +123,16 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal propertyGroup.Add(new XElement("UserSecretsId", newSecretsId)); } - projectDocument.Save(projectPath); + var settings = new XmlWriterSettings + { + Indent = true, + OmitXmlDeclaration = true, + }; + + using (var xw = XmlWriter.Create(projectPath, settings)) + { + projectDocument.Save(xw); + } context.Reporter.Output(Resources.FormatMessage_SetUserSecretsIdForProject(newSecretsId, projectPath)); } diff --git a/src/Tools/dotnet-user-secrets/test/InitCommandTest.cs b/src/Tools/dotnet-user-secrets/test/InitCommandTest.cs index 562f149ca4..ee0efce15f 100644 --- a/src/Tools/dotnet-user-secrets/test/InitCommandTest.cs +++ b/src/Tools/dotnet-user-secrets/test/InitCommandTest.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Text; +using System.Xml.Linq; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Configuration.UserSecrets.Tests; using Microsoft.Extensions.SecretManager.Tools.Internal; @@ -90,6 +91,18 @@ namespace Microsoft.Extensions.SecretManager.Tools.Tests Assert.Equal(SecretId, idResolver.Resolve(null, null)); } + [Fact] + public void DoesNotAddXmlDeclarationToProject() + { + var projectDir = _fixture.CreateProject(null); + var projectFile = Path.Combine(projectDir, "TestProject.csproj"); + + new InitCommand(null, null).Execute(MakeCommandContext(), projectDir); + + var projectDocument = XDocument.Load(projectFile); + Assert.Null(projectDocument.Declaration); + } + [Fact] public void OverridesIdForProjectWithSecretId() {