Skip to content

Commit

Permalink
Fixes #11189 - protected content not working (#11193)
Browse files Browse the repository at this point in the history
* Fixes #11189

* Fixes #11183

* Fix test Null_When_No_Content_On_PublishedRequest.

Believe this is reasonable.

* Update src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs

Co-authored-by: Paul Johnson <pmj@umbraco.com>
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
  • Loading branch information
3 people committed Sep 26, 2021
1 parent cf52b46 commit 5bfab13
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public async Task Assigns_PublishedRequest_To_UmbracoContext()
public async Task Null_When_No_Content_On_PublishedRequest()
{
IUmbracoContext umbracoContext = GetUmbracoContext(true);
IPublishedRequest request = Mock.Of<IPublishedRequest>();
IPublishedRequest request = Mock.Of<IPublishedRequest>(x => x.PublishedContent == null);

UmbracoRouteValueTransformer transformer = GetTransformerWithRunState(
Mock.Of<IUmbracoContextAccessor>(x => x.TryGetUmbracoContext(out umbracoContext)),
Expand All @@ -172,9 +172,10 @@ public async Task Null_When_No_Content_On_PublishedRequest()

var httpContext = new DefaultHttpContext();
RouteValueDictionary result = await transformer.TransformAsync(httpContext, new RouteValueDictionary());
Assert.IsNull(result);

UmbracoRouteValues routeVals = httpContext.Features.Get<UmbracoRouteValues>();
Assert.IsNull(routeVals);
Assert.AreEqual(routeVals.PublishedRequest.GetRouteResult(), UmbracoRouteResult.NotFound);
}

[Test]
Expand Down
15 changes: 15 additions & 0 deletions src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;

namespace Umbraco.Cms.Web.Common.Security
{
Expand Down Expand Up @@ -34,6 +36,19 @@ public void Configure(CookieAuthenticationOptions options)
options.LogoutPath = null;

options.CookieManager = new MemberCookieManager(_runtimeState, _umbracoRequestPaths);

options.Events = new CookieAuthenticationEvents
{
OnSignedIn = ctx =>
{
// occurs when sign in is successful and after the ticket is written to the outbound cookie
// When we are signed in with the cookie, assign the principal to the current HttpContext
ctx.HttpContext.SetPrincipalForRequest(ctx.Principal);
return Task.CompletedTask;
}
};
}
}
}
15 changes: 15 additions & 0 deletions src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
Expand Down Expand Up @@ -65,6 +67,19 @@ public async Task<UmbracoRouteValues> RewriteForPublishedContentAccessAsync(Http
{
_logger.LogDebug("EnsurePublishedContentAccess: Page is protected, check for access");

// manually authenticate the request
AuthenticateResult authResult = await httpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
if (authResult.Succeeded)
{
// set the user to the auth result. we need to do this here because this occurs
// before the authentication middleware.
// NOTE: It would be possible to just pass the authResult to the HasMemberAccessToContentAsync method
// instead of relying directly on the user assigned to the http context, and then the auth middleware
// will run anyways and assign the user. Perhaps that is a little cleaner, but would require more code
// changes right now, and really it's not any different in the end result.
httpContext.SetPrincipalForRequest(authResult.Principal);
}

publicAccessStatus = await _publicAccessChecker.HasMemberAccessToContentAsync(publishedContent.Id);
switch (publicAccessStatus)
{
Expand Down
24 changes: 13 additions & 11 deletions src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,7 @@ public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext

IPublishedRequest publishedRequest = await RouteRequestAsync(umbracoContext);

umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest);

if (!umbracoRouteValues?.PublishedRequest?.HasPublishedContent() ?? false)
{
// No content was found, not by any registered 404 handlers and
// not by the IContentLastChanceFinder. In this case we want to return
// our default 404 page but we cannot return route values now because
// it's possible that a developer is handling dynamic routes too.
// Our 404 page will be handled with the NotFoundSelectorPolicy
return null;
}
umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest);

// now we need to do some public access checks
umbracoRouteValues = await _publicAccessRequestHandler.RewriteForPublishedContentAccessAsync(httpContext, umbracoRouteValues);
Expand All @@ -155,6 +145,18 @@ public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext
return HandlePostedValues(postedInfo, httpContext);
}

UmbracoRouteResult? routeResult = umbracoRouteValues?.PublishedRequest?.GetRouteResult();

if (!routeResult.HasValue || routeResult == UmbracoRouteResult.NotFound)
{
// No content was found, not by any registered 404 handlers and
// not by the IContentLastChanceFinder. In this case we want to return
// our default 404 page but we cannot return route values now because
// it's possible that a developer is handling dynamic routes too.
// Our 404 page will be handled with the NotFoundSelectorPolicy
return null;
}

// See https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.routing.dynamicroutevaluetransformer.transformasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Mvc_Routing_DynamicRouteValueTransformer_TransformAsync_Microsoft_AspNetCore_Http_HttpContext_Microsoft_AspNetCore_Routing_RouteValueDictionary_
// We should apparenlty not be modified these values.
// So we create new ones.
Expand Down

0 comments on commit 5bfab13

Please sign in to comment.