From c9f0a47c0d688f59ce847c8c8833b34fe48bc675 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 10 Jul 2015 14:50:11 -0700 Subject: [PATCH] Empty challenge for authenticated request should result in Forbidden. --- .../AuthenticationHandler.cs | 6 ++--- .../AuthenticationTests.cs | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index aa0e411d72..d6f9ebd9ca 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -68,12 +68,12 @@ namespace Microsoft.AspNet.Server.WebListener public Task ChallengeAsync(ChallengeContext context) { + var hasEmptyChallenge = string.IsNullOrEmpty(context.AuthenticationScheme); foreach (var scheme in ListEnabledAuthSchemes()) { var authScheme = scheme.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (string.IsNullOrEmpty(context.AuthenticationScheme) || - string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) + if (hasEmptyChallenge || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) { switch (context.Behavior) { @@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener case ChallengeBehavior.Automatic: var identity = (ClaimsIdentity)_requestContext.User?.Identity; if (identity != null && identity.IsAuthenticated - && string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal)) + && (hasEmptyChallenge || string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal))) { _requestContext.Response.StatusCode = 403; context.Accept(); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 56478fc87f..e6a74f196d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -460,6 +460,30 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Theory] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials + public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType) + { + string address; + using (Utilities.CreateHttpAuthServer(authType, out address, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + return context.Authentication.ChallengeAsync(); + })) + { + var response = await SendRequestAsync(address, useDefaultCredentials: true); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + // for some reason Kerberos and Negotiate include a 2nd stage challenge. + // Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + [Theory] [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)]