Merge remote-tracking branch 'origin/v12/dev' into v13/dev
This commit is contained in:
@@ -719,6 +719,7 @@
|
||||
<key alias="by">af</key>
|
||||
<key alias="cancel">Fortryd</key>
|
||||
<key alias="cellMargin">Celle margen</key>
|
||||
<key alias="change">Skift</key>
|
||||
<key alias="choose">Vælg</key>
|
||||
<key alias="clear">Ryd</key>
|
||||
<key alias="close">Luk</key>
|
||||
|
||||
@@ -759,6 +759,7 @@
|
||||
<key alias="by">by</key>
|
||||
<key alias="cancel">Cancel</key>
|
||||
<key alias="cellMargin">Cell margin</key>
|
||||
<key alias="change">Change</key>
|
||||
<key alias="choose">Choose</key>
|
||||
<key alias="clear">Clear</key>
|
||||
<key alias="close">Close</key>
|
||||
|
||||
@@ -704,9 +704,6 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
[DataMember(Name = "packageFolder")]
|
||||
public string? PackageFolder { get; set; }
|
||||
|
||||
[DataMember(Name = "sectionAlias")]
|
||||
public string? SectionAlias { get; set; }
|
||||
}
|
||||
|
||||
private IEnumerable<PluginTree> GetPluginTrees()
|
||||
@@ -738,7 +735,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new PluginTree { Alias = tree.TreeAlias, PackageFolder = pluginController.AreaName, SectionAlias = tree.SectionAlias };
|
||||
yield return new PluginTree { Alias = tree.TreeAlias, PackageFolder = pluginController.AreaName };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -583,10 +583,10 @@ public class MediaController : ContentControllerBase
|
||||
Directory.CreateDirectory(root);
|
||||
|
||||
//must have a file
|
||||
if (file.Count == 0)
|
||||
if (file is null || file.Count == 0)
|
||||
{
|
||||
_postAddFileSemaphore.Release();
|
||||
return NotFound();
|
||||
return NotFound("No file was uploaded");
|
||||
}
|
||||
|
||||
//get the string json from the request
|
||||
@@ -769,12 +769,26 @@ public class MediaController : ContentControllerBase
|
||||
break;
|
||||
}
|
||||
|
||||
// If media type is still File then let's check if it's an image.
|
||||
// If media type is still File then let's check if it's an imageor a custom image type.
|
||||
if (mediaTypeAlias == Constants.Conventions.MediaTypes.File &&
|
||||
_imageUrlGenerator.IsSupportedImageFormat(ext))
|
||||
{
|
||||
if (allowedContentTypes.Any(mt => mt.Alias == Constants.Conventions.MediaTypes.Image))
|
||||
{
|
||||
mediaTypeAlias = Constants.Conventions.MediaTypes.Image;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMediaType? customType = allowedContentTypes.FirstOrDefault(mt =>
|
||||
mt.CompositionPropertyTypes.Any(pt =>
|
||||
pt.PropertyEditorAlias == Constants.PropertyEditors.Aliases.ImageCropper));
|
||||
|
||||
if (customType is not null)
|
||||
{
|
||||
mediaTypeAlias = customType.Alias;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -360,7 +360,7 @@ public class ApplicationTreeController : UmbracoAuthorizedApiController
|
||||
ControllerActionDescriptor? actionDescriptor = _actionDescriptorCollectionProvider.ActionDescriptors.Items
|
||||
.Cast<ControllerActionDescriptor>()
|
||||
.First(x =>
|
||||
(x.ControllerTypeInfo.FullName ?? string.Empty).Equals(controllerType.FullName) &&
|
||||
x.ControllerName.Equals(controllerName) &&
|
||||
x.ActionName == action);
|
||||
|
||||
var actionContext = new ActionContext(HttpContext, routeData, actionDescriptor);
|
||||
|
||||
@@ -3,12 +3,10 @@ using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Trees;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Trees;
|
||||
|
||||
[CoreTree]
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeTreeArea)]
|
||||
[Tree(Constants.Applications.Settings, Constants.Trees.Scripts, TreeTitle = "Scripts", SortOrder = 10, TreeGroup = Constants.Trees.Groups.Templating)]
|
||||
public class ScriptsTreeController : FileSystemTreeController
|
||||
{
|
||||
|
||||
@@ -3,12 +3,10 @@ using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Trees;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Trees;
|
||||
|
||||
[CoreTree]
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeTreeArea)]
|
||||
[Tree(Constants.Applications.Settings, Constants.Trees.Stylesheets, TreeTitle = "Stylesheets", SortOrder = 9, TreeGroup = Constants.Trees.Groups.Templating)]
|
||||
public class StylesheetsTreeController : FileSystemTreeController
|
||||
{
|
||||
|
||||
@@ -47,15 +47,14 @@ public static class UrlHelperExtensions
|
||||
string nodeId,
|
||||
FormCollection? queryStrings)
|
||||
{
|
||||
var actionName = "GetNodes";
|
||||
var actionUrl = urlHelper.GetUmbracoApiService(umbracoApiControllerTypeCollection, actionName, treeType);
|
||||
actionUrl = StartOrContinueQueryString(actionUrl, actionName);
|
||||
|
||||
// Now we need to append the query strings
|
||||
// Always ignore the custom start node id when generating URLs for tree nodes since this is a custom once-only parameter
|
||||
// that should only ever be used when requesting a tree to render (root), not a tree node
|
||||
actionUrl += "id=" + nodeId.EnsureEndsWith('&') + queryStrings?.ToQueryString("id", TreeQueryStringParameters.StartNodeId);
|
||||
var actionUrl = urlHelper.GetUmbracoApiService(umbracoApiControllerTypeCollection, "GetNodes", treeType)?
|
||||
.EnsureEndsWith('?');
|
||||
|
||||
//now we need to append the query strings
|
||||
actionUrl += "id=" + nodeId.EnsureEndsWith('&') + queryStrings?.ToQueryString("id",
|
||||
//Always ignore the custom start node id when generating URLs for tree nodes since this is a custom once-only parameter
|
||||
// that should only ever be used when requesting a tree to render (root), not a tree node
|
||||
TreeQueryStringParameters.StartNodeId);
|
||||
return actionUrl;
|
||||
}
|
||||
|
||||
@@ -66,29 +65,11 @@ public static class UrlHelperExtensions
|
||||
string nodeId,
|
||||
FormCollection? queryStrings)
|
||||
{
|
||||
var actionName = "GetMenu";
|
||||
var actionUrl = urlHelper.GetUmbracoApiService(umbracoApiControllerTypeCollection, actionName, treeType);
|
||||
actionUrl = StartOrContinueQueryString(actionUrl, actionName);
|
||||
var actionUrl = urlHelper.GetUmbracoApiService(umbracoApiControllerTypeCollection, "GetMenu", treeType)?
|
||||
.EnsureEndsWith('?');
|
||||
|
||||
// now we need to append the query strings
|
||||
//now we need to append the query strings
|
||||
actionUrl += "id=" + nodeId.EnsureEndsWith('&') + queryStrings?.ToQueryString("id");
|
||||
return actionUrl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the provided string already includes a querystring fragment
|
||||
/// If so, result has "&" appended, else has "?" appended.
|
||||
/// </summary>
|
||||
/// <param name="actionUrl"></param>
|
||||
/// <param name="delimiter"></param>
|
||||
/// <returns></returns>
|
||||
private static string? StartOrContinueQueryString(string? actionUrl, string? delimiter)
|
||||
{
|
||||
if (actionUrl is null)
|
||||
{
|
||||
return actionUrl;
|
||||
}
|
||||
|
||||
return actionUrl.EnsureEndsWith(actionUrl.Contains($"{delimiter}?") ? "&" : "?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,14 +60,14 @@ public class UmbracoMemberAuthorizeFilter : IAsyncAuthorizationFilter
|
||||
{
|
||||
context.HttpContext.SetReasonPhrase(
|
||||
"Resource restricted: the member is not of a permitted type or group.");
|
||||
context.HttpContext.Response.StatusCode = 403;
|
||||
context.Result = new ForbidResult();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.HttpContext.SetReasonPhrase(
|
||||
"Resource restricted: the member is not logged in.");
|
||||
context.Result = new UnauthorizedResult();
|
||||
context.HttpContext.Response.StatusCode = 401;
|
||||
context.Result = new ForbidResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.Common.Security;
|
||||
@@ -58,7 +60,16 @@ public sealed class ConfigureMemberCookieOptions : IConfigureNamedOptions<Cookie
|
||||
},
|
||||
OnRedirectToAccessDenied = ctx =>
|
||||
{
|
||||
ctx.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
// When the controller is an UmbracoAPIController, we want to return a StatusCode instead of a redirect.
|
||||
// All other cases should use the default Redirect of the CookieAuthenticationEvent.
|
||||
var controllerDescriptor = ctx.HttpContext.GetEndpoint()?.Metadata
|
||||
.OfType<ControllerActionDescriptor>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (!controllerDescriptor?.ControllerTypeInfo.IsSubclassOf(typeof(UmbracoApiController)) ?? false)
|
||||
{
|
||||
new CookieAuthenticationEvents().OnRedirectToAccessDenied(ctx);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
|
||||
@@ -32,7 +32,7 @@ Umbraco.Sys.ServerVariables = {
|
||||
},
|
||||
umbracoPlugins: {
|
||||
trees: [
|
||||
{ alias: "myTree", packageFolder: "MyPackage", sectionAlias: "myPackageSectionAlias" }
|
||||
{ alias: "myTree", packageFolder: "MyPackage" }
|
||||
]
|
||||
},
|
||||
isDebuggingEnabled: true,
|
||||
|
||||
@@ -344,10 +344,14 @@ function clipboardService($window, notificationsService, eventsService, localSto
|
||||
// Clean up each entry
|
||||
var copiedDatas = datas.map(data => prepareEntryForStorage(type, data, firstLevelClearupMethod));
|
||||
|
||||
// remove previous copies of this entry:
|
||||
// remove previous copies of this entry (Make sure to not remove copies from unsaved content):
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== uniqueKey;
|
||||
if (entry.unique === 0) {
|
||||
return displayLabel !== entry.label;
|
||||
} else {
|
||||
return entry.unique !== uniqueKey;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -616,7 +616,7 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
|
||||
if (!treeAlias) {
|
||||
throw "Could not get tree alias for node " + args.node.id;
|
||||
}
|
||||
templateUrl = this.getTreeTemplateUrl(treeAlias, args.action.alias, args.node.section);
|
||||
templateUrl = this.getTreeTemplateUrl(treeAlias, args.action.alias);
|
||||
}
|
||||
|
||||
setMode("dialog");
|
||||
@@ -633,7 +633,6 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
|
||||
*
|
||||
* @param {string} treeAlias the alias of the tree to look up
|
||||
* @param {string} action the view file name
|
||||
* @param {string} sectionAlias the alias of the current section
|
||||
* @description
|
||||
* creates the templateUrl based on treeAlias and action
|
||||
* by convention we will look into the /views/{treetype}/{action}.html
|
||||
@@ -641,8 +640,8 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
|
||||
* we will also check for a 'packageName' for the current tree, if it exists then the convention will be:
|
||||
* for example: /App_Plugins/{mypackage}/backoffice/{treetype}/create.html
|
||||
*/
|
||||
getTreeTemplateUrl: function (treeAlias, action, sectionAlias) {
|
||||
var packageTreeFolder = treeService.getTreePackageFolder(treeAlias, sectionAlias);
|
||||
getTreeTemplateUrl: function (treeAlias, action) {
|
||||
var packageTreeFolder = treeService.getTreePackageFolder(treeAlias);
|
||||
if (packageTreeFolder) {
|
||||
return (Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath +
|
||||
"/" + packageTreeFolder +
|
||||
|
||||
@@ -166,27 +166,23 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
|
||||
*
|
||||
* @description
|
||||
* Determines if the current tree is a plugin tree and if so returns the package folder it has declared
|
||||
* so we know where to find its views, otherwise it will just return undefined.
|
||||
* so we know where to find it's views, otherwise it will just return undefined.
|
||||
*
|
||||
* @param {String} treeAlias The tree alias to check
|
||||
* @param {String} sectionAlias The current section
|
||||
*/
|
||||
getTreePackageFolder: function (treeAlias, sectionAlias) {
|
||||
getTreePackageFolder: function (treeAlias) {
|
||||
//we determine this based on the server variables
|
||||
if (!Umbraco.Sys.ServerVariables.umbracoPlugins || !Utilities.isArray(Umbraco.Sys.ServerVariables.umbracoPlugins.trees)) {
|
||||
return undefined;
|
||||
}
|
||||
if (Umbraco.Sys.ServerVariables.umbracoPlugins &&
|
||||
Umbraco.Sys.ServerVariables.umbracoPlugins.trees &&
|
||||
Utilities.isArray(Umbraco.Sys.ServerVariables.umbracoPlugins.trees)) {
|
||||
|
||||
let found;
|
||||
if (sectionAlias !== undefined) {
|
||||
found = Umbraco.Sys.ServerVariables.umbracoPlugins.trees.find(item =>
|
||||
invariantEquals(item.alias, treeAlias) && invariantEquals(item.sectionAlias, sectionAlias));
|
||||
} else {
|
||||
found = Umbraco.Sys.ServerVariables.umbracoPlugins.trees.find(item =>
|
||||
invariantEquals(item.alias, treeAlias));
|
||||
}
|
||||
var found = _.find(Umbraco.Sys.ServerVariables.umbracoPlugins.trees, function (item) {
|
||||
return invariantEquals(item.alias, treeAlias);
|
||||
});
|
||||
|
||||
return found ? found.packageFolder : undefined;
|
||||
return found ? found.packageFolder : undefined;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -872,7 +868,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
|
||||
//start
|
||||
var wrappedPromise = doSync();
|
||||
|
||||
//then wrap it
|
||||
//then wrap it
|
||||
wrappedPromise.then(function (args) {
|
||||
deferred.resolve(args);
|
||||
}, function (args) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
window.app.config(function ($routeProvider) {
|
||||
|
||||
|
||||
/**
|
||||
* This determines if the route can continue depending on authentication and initialization requirements
|
||||
* @param {boolean} authRequired If true, it checks if the user is authenticated and will resolve successfully
|
||||
@@ -117,9 +117,9 @@ window.app.config(function ($routeProvider) {
|
||||
template: "<div ng-include='templateUrl'></div>",
|
||||
//This controller will execute for this route, then we can execute some code in order to set the template Url
|
||||
controller: function ($scope, $route, $routeParams, $location, sectionService) {
|
||||
|
||||
|
||||
//We are going to check the currently loaded sections for the user and if the section we are navigating
|
||||
//to has a custom route path we'll use that
|
||||
//to has a custom route path we'll use that
|
||||
sectionService.getSectionsForUser().then(function(sections) {
|
||||
//find the one we're requesting
|
||||
var found = _.find(sections, function(s) {
|
||||
@@ -175,9 +175,8 @@ window.app.config(function ($routeProvider) {
|
||||
if ($routeParams.section.toLowerCase() === "users" && $routeParams.tree.toLowerCase() === "users" && usersPages.indexOf($routeParams.method.toLowerCase()) === -1) {
|
||||
$scope.templateUrl = "views/users/overview.html";
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.templateUrl = navigationService.getTreeTemplateUrl($routeParams.tree, $routeParams.method, $routeParams.section);
|
||||
}
|
||||
$scope.templateUrl = navigationService.getTreeTemplateUrl($routeParams.tree, $routeParams.method);
|
||||
},
|
||||
reloadOnSearch: false,
|
||||
resolve: canRoute(true)
|
||||
@@ -191,9 +190,8 @@ window.app.config(function ($routeProvider) {
|
||||
if (!$routeParams.tree || !$routeParams.method) {
|
||||
$scope.templateUrl = "views/common/dashboard.html";
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.templateUrl = navigationService.getTreeTemplateUrl($routeParams.tree, $routeParams.method, $routeParams.section);
|
||||
}
|
||||
$scope.templateUrl = navigationService.getTreeTemplateUrl($routeParams.tree, $routeParams.method);
|
||||
},
|
||||
reloadOnSearch: false,
|
||||
reloadOnUrl: false,
|
||||
@@ -201,7 +199,7 @@ window.app.config(function ($routeProvider) {
|
||||
})
|
||||
.otherwise({ redirectTo: '/login' });
|
||||
}).config(function ($locationProvider) {
|
||||
|
||||
|
||||
$locationProvider.html5Mode(false); //turn html5 mode off
|
||||
$locationProvider.hashPrefix('');
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
ng-repeat="subView in subViews track by subView.alias"
|
||||
ng-class="'sub-view-' + subView.name"
|
||||
val-sub-view="subView"
|
||||
ng-if="subView.active"
|
||||
ng-show="subView.active"
|
||||
>
|
||||
<div class="umb-editor-sub-view__content" ng-include="subView.view"></div>
|
||||
</div>
|
||||
|
||||
@@ -298,13 +298,13 @@ describe('tree service tests', function () {
|
||||
|
||||
it('can find a plugin based tree', function () {
|
||||
//we know this exists in the mock umbraco server vars
|
||||
var found = treeService.getTreePackageFolder("myTree", "MyPackageSectionAlias");
|
||||
var found = treeService.getTreePackageFolder("myTree");
|
||||
expect(found).toBe("MyPackage");
|
||||
});
|
||||
|
||||
it('returns undefined for a not found tree', function () {
|
||||
//we know this does not exist in the mock umbraco server vars
|
||||
var found = treeService.getTreePackageFolder("asdfasdf", "fdsafdsa");
|
||||
var found = treeService.getTreePackageFolder("asdfasdf");
|
||||
expect(found).not.toBeDefined();
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Tests.Integration.TestServerTest;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Cms.Web.Common.Filters;
|
||||
using Umbraco.Cms.Web.Common.Security;
|
||||
using Umbraco.Cms.Web.Website.Controllers;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.Website.Security
|
||||
{
|
||||
public class MemberAuthorizeTests : UmbracoTestServerTestBase
|
||||
{
|
||||
private Mock<IMemberManager> _memberManagerMock = new();
|
||||
|
||||
protected override void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
_memberManagerMock = new Mock<IMemberManager>();
|
||||
services.Remove(new ServiceDescriptor(typeof(IMemberManager), typeof(MemberManager), ServiceLifetime.Scoped));
|
||||
services.Remove(new ServiceDescriptor(typeof(MemberManager), ServiceLifetime.Scoped));
|
||||
services.AddScoped(_ => _memberManagerMock.Object);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Secure_SurfaceController_Should_Return_Redirect_WhenNotLoggedIn()
|
||||
{
|
||||
_memberManagerMock.Setup(x => x.IsLoggedIn()).Returns(false);
|
||||
|
||||
var url = PrepareSurfaceControllerUrl<TestSurfaceController>(x => x.Secure());
|
||||
|
||||
var response = await Client.GetAsync(url);
|
||||
|
||||
var cookieAuthenticationOptions = Services.GetService<IOptions<CookieAuthenticationOptions>>();
|
||||
Assert.AreEqual(HttpStatusCode.Redirect, response.StatusCode);
|
||||
Assert.AreEqual(cookieAuthenticationOptions.Value.AccessDeniedPath.ToString(), response.Headers.Location?.AbsolutePath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Secure_SurfaceController_Should_Return_Redirect_WhenNotAuthorized()
|
||||
{
|
||||
_memberManagerMock.Setup(x => x.IsLoggedIn()).Returns(true);
|
||||
_memberManagerMock.Setup(x => x.IsMemberAuthorizedAsync(
|
||||
It.IsAny<IEnumerable<string>>(),
|
||||
It.IsAny<IEnumerable<string>>(),
|
||||
It.IsAny<IEnumerable<int>>()))
|
||||
.ReturnsAsync(false);
|
||||
|
||||
var url = PrepareSurfaceControllerUrl<TestSurfaceController>(x => x.Secure());
|
||||
|
||||
var response = await Client.GetAsync(url);
|
||||
|
||||
var cookieAuthenticationOptions = Services.GetService<IOptions<CookieAuthenticationOptions>>();
|
||||
Assert.AreEqual(HttpStatusCode.Redirect, response.StatusCode);
|
||||
Assert.AreEqual(cookieAuthenticationOptions.Value.AccessDeniedPath.ToString(), response.Headers.Location?.AbsolutePath);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task Secure_ApiController_Should_Return_Unauthorized_WhenNotLoggedIn()
|
||||
{
|
||||
_memberManagerMock.Setup(x => x.IsLoggedIn()).Returns(false);
|
||||
var url = PrepareApiControllerUrl<TestApiController>(x => x.Secure());
|
||||
|
||||
var response = await Client.GetAsync(url);
|
||||
|
||||
Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Secure_ApiController_Should_Return_Forbidden_WhenNotAuthorized()
|
||||
{
|
||||
_memberManagerMock.Setup(x => x.IsLoggedIn()).Returns(true);
|
||||
_memberManagerMock.Setup(x => x.IsMemberAuthorizedAsync(
|
||||
It.IsAny<IEnumerable<string>>(),
|
||||
It.IsAny<IEnumerable<string>>(),
|
||||
It.IsAny<IEnumerable<int>>()))
|
||||
.ReturnsAsync(false);
|
||||
|
||||
var url = PrepareApiControllerUrl<TestApiController>(x => x.Secure());
|
||||
|
||||
var response = await Client.GetAsync(url);
|
||||
|
||||
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public class TestSurfaceController : SurfaceController
|
||||
{
|
||||
public TestSurfaceController(
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
ServiceContext services,
|
||||
AppCaches appCaches,
|
||||
IProfilingLogger profilingLogger,
|
||||
IPublishedUrlProvider publishedUrlProvider)
|
||||
: base(
|
||||
umbracoContextAccessor,
|
||||
databaseFactory,
|
||||
services,
|
||||
appCaches,
|
||||
profilingLogger,
|
||||
publishedUrlProvider)
|
||||
{
|
||||
}
|
||||
|
||||
[UmbracoMemberAuthorize]
|
||||
public IActionResult Secure() => NoContent();
|
||||
}
|
||||
|
||||
public class TestApiController : UmbracoApiController
|
||||
{
|
||||
[UmbracoMemberAuthorize]
|
||||
public IActionResult Secure() => NoContent();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user