Merge remote-tracking branch 'oqtane/dev' into dev

This commit is contained in:
Leigh Pointer 2023-03-10 16:42:44 +01:00
commit b9e352cbcb
21 changed files with 423 additions and 284 deletions

View File

@ -9,189 +9,194 @@
@inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<TabStrip>
<TabPanel Name="Definition" ResourceKey="Definition">
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="The name of the module" ResourceKey="Name">Name: </Label>
<div class="col-sm-9">
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="description" HelpText="The description of the module" ResourceKey="Description">Description: </Label>
<div class="col-sm-9">
<textarea id="description" class="form-control" @bind="@_description" rows="2" maxlength="2000" required></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
<div class="col-sm-9">
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
</div>
</div>
</div>
</form>
<Section Name="Information" ResourceKey="Information">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="moduledefinitionname" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
<div class="col-sm-9">
<input id="moduledefinitionname" class="form-control" @bind="@_moduledefinitionname" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="version" HelpText="The version of the module" ResourceKey="Version">Version: </Label>
<div class="col-sm-9">
<input id="version" class="form-control" @bind="@_version" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
<div class="col-sm-9">
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
@if (_initialized)
{
<TabStrip>
<TabPanel Name="Definition" ResourceKey="Definition">
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="The name of the module" ResourceKey="Name">Name: </Label>
<div class="col-sm-9">
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="description" HelpText="The description of the module" ResourceKey="Description">Description: </Label>
<div class="col-sm-9">
<textarea id="description" class="form-control" @bind="@_description" rows="2" maxlength="2000" required></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
<div class="col-sm-9">
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
</div>
</div>
</div>
</form>
<Section Name="Information" ResourceKey="Information">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="moduledefinitionname" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
<div class="col-sm-9">
<input id="moduledefinitionname" class="form-control" @bind="@_moduledefinitionname" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="version" HelpText="The version of the module" ResourceKey="Version">Version: </Label>
<div class="col-sm-9">
<input id="version" class="form-control" @bind="@_version" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
<div class="col-sm-9">
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the module" ResourceKey="Owner">Owner: </Label>
<div class="col-sm-9">
<input id="owner" class="form-control" @bind="@_owner" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="url" HelpText="The reference url of the module" ResourceKey="ReferenceUrl">Reference Url: </Label>
<div class="col-sm-9">
<input id="url" class="form-control" @bind="@_url" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="contact" HelpText="The contact for the module" ResourceKey="Contact">Contact: </Label>
<div class="col-sm-9">
<input id="contact" class="form-control" @bind="@_contact" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="license" HelpText="The module license terms" ResourceKey="License">License: </Label>
<div class="col-sm-9">
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="runtimes" HelpText="The Blazor runtimes which this module supports" ResourceKey="Runtimes">Runtimes: </Label>
<div class="col-sm-9">
<input id="runtimes" class="form-control" @bind="@_runtimes" disabled />
</div>
</div>
</div>
</Section>
<br />
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
</TabPanel>
<TabPanel Name="Permissions" ResourceKey="Permissions">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the module" ResourceKey="Owner">Owner: </Label>
<div class="col-sm-9">
<input id="owner" class="form-control" @bind="@_owner" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="url" HelpText="The reference url of the module" ResourceKey="ReferenceUrl">Reference Url: </Label>
<div class="col-sm-9">
<input id="url" class="form-control" @bind="@_url" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="contact" HelpText="The contact for the module" ResourceKey="Contact">Contact: </Label>
<div class="col-sm-9">
<input id="contact" class="form-control" @bind="@_contact" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="license" HelpText="The module license terms" ResourceKey="License">License: </Label>
<div class="col-sm-9">
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="runtimes" HelpText="The Blazor runtimes which this module supports" ResourceKey="Runtimes">Runtimes: </Label>
<div class="col-sm-9">
<input id="runtimes" class="form-control" @bind="@_runtimes" disabled />
</div>
</div>
</div>
</Section>
<br />
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
</TabPanel>
<TabPanel Name="Permissions" ResourceKey="Permissions">
<div class="container">
<div class="row mb-1 align-items-center">
<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" PermissionList="@_permissions" @ref="_permissionGrid" />
</div>
</div>
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
</TabPanel>
<TabPanel Name="Translations" ResourceKey="Translations">
@if (_languages != null && _languages.Count > 0)
{
<Pager Items="@_languages">
<Header>
<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" PermissionList="@_permissions" @ref="_permissionGrid" />
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
</TabPanel>
<TabPanel Name="Translations" ResourceKey="Translations">
@if (_languages != null && _languages.Count > 0)
{
<Pager Items="@_languages">
<Header>
<th>@SharedLocalizer["Name"]</th>
<th>@Localizer["Code"]</th>
<th style="width: 1px;">@Localizer["Version"]</th>
<th style="width: 1px;">&nbsp;</th>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.Code</td>
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
<td>
@switch (TranslationAvailable(_packagename + "." + context.Code, context.Version))
{
case "install":
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Download"]</button>
break;
case "upgrade":
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Upgrade"]</button>
break;
}
</td>
</Row>
</Pager>
@if (_install)
{
<button type="button" class="btn btn-success" @onclick="InstallTranslations">@SharedLocalizer["Install"]</button>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.Code</td>
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
<td>
@switch (TranslationAvailable(_packagename + "." + context.Code, context.Version))
{
case "install":
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Download"]</button>
break;
case "upgrade":
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Upgrade"]</button>
break;
}
</td>
</Row>
</Pager>
@if (_install)
{
<button type="button" class="btn btn-success" @onclick="InstallTranslations">@SharedLocalizer["Install"]</button>
}
}
}
else
{
<br />
<div class="mx-auto text-center">
@if (string.IsNullOrEmpty(_packagename))
{
@Localizer["Search.PackageNameMissing"]
}
else
{
@Localizer["Search.NoResults"]
}
</div>
<br />
}
</TabPanel>
</TabStrip>
else
{
<br />
<div class="mx-auto text-center">
@if (string.IsNullOrEmpty(_packagename))
{
@Localizer["Search.PackageNameMissing"]
}
else
{
@Localizer["Search.NoResults"]
}
</div>
<br />
}
</TabPanel>
</TabStrip>
@if (_package != null)
{
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
</div>
<div class="modal-body">
<p style="height: 200px; overflow-y: scroll;">
<h4 style="display: inline;"><a href="@_package.ProductUrl" target="_new">@_package.Name</a></h4><br />
@SharedLocalizer["Search.By"]:&nbsp;&nbsp;<strong><a href="@_package.OwnerUrl" target="new">@_package.Owner</a></strong><br />
@(_package.Description.Length > 400 ? (_package.Description.Substring(0, 400) + "...") : _package.Description)<br />
<strong>@(String.Format("{0:n0}", _package.Downloads))</strong> @SharedLocalizer["Search.Downloads"]&nbsp;&nbsp;|&nbsp;&nbsp;
@SharedLocalizer["Search.Released"]: <strong>@_package.ReleaseDate.ToString("MMM dd, yyyy")</strong>&nbsp;&nbsp;|&nbsp;&nbsp;
@SharedLocalizer["Search.Version"]: <strong>@_package.Version</strong>
@((MarkupString)(!string.IsNullOrEmpty(_package.PackageUrl) ? "&nbsp;&nbsp;|&nbsp;&nbsp;" + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(_package.PackageUrl).Host + "</strong>" : ""))
<br /><br />
@if (!string.IsNullOrEmpty(_package.License))
{
@((MarkupString)_package.License.Replace("\n", "<br />"))
}
else
{
@SharedLocalizer["License Not Specified"]
}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
@if (_package != null)
{
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
</div>
<div class="modal-body">
<p style="height: 200px; overflow-y: scroll;">
<h4 style="display: inline;"><a href="@_package.ProductUrl" target="_new">@_package.Name</a></h4><br />
@SharedLocalizer["Search.By"]:&nbsp;&nbsp;<strong><a href="@_package.OwnerUrl" target="new">@_package.Owner</a></strong><br />
@(_package.Description.Length > 400 ? (_package.Description.Substring(0, 400) + "...") : _package.Description)<br />
<strong>@(String.Format("{0:n0}", _package.Downloads))</strong> @SharedLocalizer["Search.Downloads"]&nbsp;&nbsp;|&nbsp;&nbsp;
@SharedLocalizer["Search.Released"]: <strong>@_package.ReleaseDate.ToString("MMM dd, yyyy")</strong>&nbsp;&nbsp;|&nbsp;&nbsp;
@SharedLocalizer["Search.Version"]: <strong>@_package.Version</strong>
@((MarkupString)(!string.IsNullOrEmpty(_package.PackageUrl) ? "&nbsp;&nbsp;|&nbsp;&nbsp;" + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(_package.PackageUrl).Host + "</strong>" : ""))
<br /><br />
@if (!string.IsNullOrEmpty(_package.License))
{
@((MarkupString)_package.License.Replace("\n", "<br />"))
}
else
{
@SharedLocalizer["License Not Specified"]
}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
</div>
</div>
</div>
</div>
</div>
</div>
}
}
@code {
private bool _initialized = false;
private ElementReference form;
private bool validated = false;
private int _moduleDefinitionId;
@ -262,6 +267,8 @@
}
_languages = _languages.OrderBy(item => item.Name).ToList();
}
_initialized = true;
}
}
catch (Exception ex)

View File

@ -294,6 +294,12 @@ else
<input id="roleclaimtype" class="form-control" @bind="@_roleclaimtype" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="profileclaimtypes" HelpText="A comma delimited list of user profile claims provided by the provider, as well as mappings to your user profile definition. For example if the provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'." ResourceKey="ProfileClaimTypes">User Profile Claims:</Label>
<div class="col-sm-9">
<input id="profileclaimtypes" class="form-control" @bind="@_profileclaimtypes" />
</div>
</div>
}
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="domainfilter" HelpText="Provide any email domain filter criteria (separated by commas). Domains to exclude should be prefixed with an exclamation point (!). For example 'microsoft.com,!hotmail.com' would include microsoft.com email addresses but not hotmail.com email addresses." ResourceKey="DomainFilter">Domain Filter:</Label>
@ -395,6 +401,7 @@ else
private string _identifierclaimtype;
private string _emailclaimtype;
private string _roleclaimtype;
private string _profileclaimtypes;
private string _domainfilter;
private string _createusers;
@ -449,6 +456,7 @@ else
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
_roleclaimtype = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimType", "");
_profileclaimtypes = SettingService.GetSetting(settings, "ExternalLogin:ProfileClaimTypes", "");
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
@ -568,6 +576,7 @@ else
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimType", _roleclaimtype, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:ProfileClaimTypes", _profileclaimtypes, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true);

View File

@ -62,7 +62,7 @@
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
[Parameter]
public string Permissions { get; set; } // optional - can be used to specify permissions (deprecated - use PermissionList)
public string Permissions { get; set; } // deprecated - use PermissionList instead
[Parameter]
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions

View File

@ -53,7 +53,7 @@
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
[Parameter]
public string Permissions { get; set; } // optional - can be used to specify permissions (deprecated - use PermissionList)
public string Permissions { get; set; } // deprecated - use PermissionList instead
[Parameter]
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions

View File

@ -138,7 +138,7 @@
// initialize permissions
_permissions = new List<Permission>();
if (PermissionList.Any())
if (PermissionList != null && PermissionList.Any())
{
foreach (var permission in PermissionList)
{
@ -167,7 +167,7 @@
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], role, null, true));
}
// ensure admin access
if (!_permissions.Any(item => item.EntityName == segments[0] && item.PermissionName == segments[1] && item.Role.Name == RoleNames.Admin))
if (!_permissions.Any(item => item.EntityName == segments[0] && item.PermissionName == segments[1] && item.RoleName == RoleNames.Admin))
{
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], RoleNames.Admin, null, true));
}
@ -203,7 +203,7 @@
bool? isauthorized = null;
if (roleName != "")
{
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.Role.Name == roleName);
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
if (permission != null)
{
isauthorized = permission.IsAuthorized;
@ -243,7 +243,7 @@
{
if (roleName != "")
{
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.Role.Name == roleName);
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
if (permission != null)
{
_permissions.Remove(permission);
@ -307,7 +307,7 @@
{
// remove deny all users, unauthenticated, and registered users
var permissions = _permissions.Where(item => !item.IsAuthorized &&
(item.Role.Name == RoleNames.Everyone || item.Role.Name == RoleNames.Unauthenticated || item.Role.Name == RoleNames.Registered)).ToList();
(item.RoleName == RoleNames.Everyone || item.RoleName == RoleNames.Unauthenticated || item.RoleName == RoleNames.Registered)).ToList();
foreach (var permission in permissions)
{
_permissions.Remove(permission);
@ -316,7 +316,7 @@
{
// remove deny administrators and host users
permissions = _permissions.Where(item => !item.IsAuthorized &&
(item.Role.Name == RoleNames.Admin || item.Role.Name == RoleNames.Host)).ToList();
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)).ToList();
foreach (var permission in permissions)
{
_permissions.Remove(permission);
@ -325,7 +325,7 @@
{
// add administrators role if neither host or administrator is assigned
if (!_permissions.Any(item => item.EntityName == GetEntityName(permissionname) && item.PermissionName == GetPermissionName(permissionname) &&
(item.Role.Name == RoleNames.Admin || item.Role.Name == RoleNames.Host)))
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)))
{
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionname), GetPermissionName(permissionname), RoleNames.Admin, null, true));
}

View File

@ -387,7 +387,13 @@
<data name="RoleClaimType.HelpText" xml:space="preserve">
<value>Optionally provide the name of the role claim provided by the identity provider. These roles will be used in addition to any internal user roles assigned within the site.</value>
</data>
<data name="RoleClaimType.Text" xml:space="preserve">
<value>Role Claim Type:</value>
<data name="RoleClaimType.Text" xml:space="preserve">
<value>Role Claim:</value>
</data>
<data name="ProfileClaimTypes.HelpText" xml:space="preserve">
<value>Optionally provide a comma delimited list of user profile claims provided by the identity provider, as well as mappings to your user profile definition. For example if the identity provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'.</value>
</data>
<data name="ProfileClaimTypes.Text" xml:space="preserve">
<value>User Profile Claims:</value>
</data>
</root>

View File

@ -44,7 +44,7 @@ namespace Oqtane.Themes.Controls
}
actionList.Add(new ActionViewModel { Icon = Icons.Trash, Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) });
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerManagerType != "")
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.IsPortable)
{
actionList.Add(new ActionViewModel { Name = "" });
actionList.Add(new ActionViewModel { Icon = Icons.CloudUpload, Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import") });
@ -137,11 +137,11 @@ namespace Oqtane.Themes.Controls
private async Task<string> Publish(string url, PageModule pagemodule)
{
var permissions = pagemodule.Module.PermissionList;
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone))
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
{
permissions.Add(new Permission(ModuleState.SiteId, EntityNames.Page, pagemodule.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
}
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered))
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
{
permissions.Add(new Permission(ModuleState.SiteId, EntityNames.Page, pagemodule.PageId, PermissionNames.View, RoleNames.Registered, null, true));
}
@ -153,13 +153,13 @@ namespace Oqtane.Themes.Controls
private async Task<string> Unpublish(string url, PageModule pagemodule)
{
var permissions = pagemodule.Module.PermissionList;
if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone))
if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
{
permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone));
permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone));
}
if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered))
if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
{
permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered));
permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered));
}
pagemodule.Module.PermissionList = permissions;
await ModuleService.UpdateModuleAsync(pagemodule.Module);

View File

@ -537,11 +537,11 @@
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
{
var permissions = PageState.Page.PermissionList;
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone))
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
{
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
}
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered))
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
{
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true));
}

View File

@ -47,6 +47,7 @@ namespace Oqtane.Controllers
int SiteId;
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
{
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(SiteId).ToList();
List<Setting> settings = _settings.GetSettings(EntityNames.Module).ToList();
foreach (PageModule pagemodule in _pageModules.GetPageModules(SiteId))
@ -74,6 +75,8 @@ namespace Oqtane.Controllers
module.Order = pagemodule.Order;
module.ContainerType = pagemodule.ContainerType;
module.ModuleDefinition = FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.PermissionList))
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
@ -92,6 +95,29 @@ namespace Oqtane.Controllers
return modules;
}
private ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition)
{
if (moduleDefinition != null)
{
moduleDefinition.Description = "";
moduleDefinition.Categories = "";
moduleDefinition.Version = "";
moduleDefinition.Owner = "";
moduleDefinition.Url = "";
moduleDefinition.Contact = "";
moduleDefinition.License = "";
moduleDefinition.Dependencies = "";
moduleDefinition.PermissionNames = "";
moduleDefinition.ServerManagerType = "";
moduleDefinition.ReleaseVersions = "";
moduleDefinition.PackageName = "";
moduleDefinition.AssemblyName = "";
moduleDefinition.PermissionList = null;
moduleDefinition.Template = "";
}
return moduleDefinition;
}
// GET api/<controller>/5
[HttpGet("{id}")]
public Module Get(int id)
@ -100,7 +126,7 @@ namespace Oqtane.Controllers
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, module.PermissionList))
{
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(module.SiteId).ToList();
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
module.ModuleDefinition = FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
module.Settings = _settings.GetSettings(EntityNames.Module, id)
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, module.PermissionList))
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);

View File

@ -13,6 +13,7 @@ using System.Globalization;
using Microsoft.Extensions.Caching.Memory;
using Oqtane.Extensions;
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace Oqtane.Controllers
{
@ -128,7 +129,8 @@ namespace Oqtane.Controllers
module.Order = pagemodule.Order;
module.ContainerType = pagemodule.ContainerType;
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
module.ModuleDefinition = FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.PermissionList))
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
@ -152,6 +154,29 @@ namespace Oqtane.Controllers
}
}
private ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition)
{
if (moduleDefinition != null)
{
moduleDefinition.Description = "";
moduleDefinition.Categories = "";
moduleDefinition.Version = "";
moduleDefinition.Owner = "";
moduleDefinition.Url = "";
moduleDefinition.Contact = "";
moduleDefinition.License = "";
moduleDefinition.Dependencies = "";
moduleDefinition.PermissionNames = "";
moduleDefinition.ServerManagerType = "";
moduleDefinition.ReleaseVersions = "";
moduleDefinition.PackageName = "";
moduleDefinition.AssemblyName = "";
moduleDefinition.PermissionList = null;
moduleDefinition.Template = "";
}
return moduleDefinition;
}
// POST api/<controller>
[HttpPost]
[Authorize(Roles = RoleNames.Host)]

View File

@ -197,7 +197,7 @@ namespace Oqtane.Extensions
}
// validate user
var identity = await ValidateUser(email, id, claims, context.HttpContext);
var identity = await ValidateUser(email, id, claims, context.HttpContext, context.Principal);
if (identity.Label == ExternalLoginStatus.Success)
{
identity.AddClaim(new Claim("access_token", context.AccessToken));
@ -232,7 +232,7 @@ namespace Oqtane.Extensions
var claims = string.Join(", ", context.Principal.Claims.Select(item => item.Type).ToArray());
// validate user
var identity = await ValidateUser(email, id, claims, context.HttpContext);
var identity = await ValidateUser(email, id, claims, context.HttpContext, context.Principal);
if (identity.Label == ExternalLoginStatus.Success)
{
// external roles
@ -278,7 +278,7 @@ namespace Oqtane.Extensions
return Task.CompletedTask;
}
private static async Task<ClaimsIdentity> ValidateUser(string email, string id, string claims, HttpContext httpContext)
private static async Task<ClaimsIdentity> ValidateUser(string email, string id, string claims, HttpContext httpContext, ClaimsPrincipal claimsPrincipal)
{
var _logger = httpContext.RequestServices.GetRequiredService<ILogManager>();
ClaimsIdentity identity = new ClaimsIdentity(Constants.AuthenticationScheme);
@ -427,6 +427,40 @@ namespace Oqtane.Extensions
user.LastLoginOn = DateTime.UtcNow;
user.LastIPAddress = httpContext.Connection.RemoteIpAddress.ToString();
_users.UpdateUser(user);
// user profile claims
if (!string.IsNullOrEmpty(httpContext.GetSiteSettings().GetValue("ExternalLogin:ProfileClaimTypes", "")))
{
var _settings = httpContext.RequestServices.GetRequiredService<ISettingRepository>();
var _profiles = httpContext.RequestServices.GetRequiredService<IProfileRepository>();
var profiles = _profiles.GetProfiles(user.SiteId);
foreach (var mapping in httpContext.GetSiteSettings().GetValue("ExternalLogin:ProfileClaimTypes", "").Split(',', StringSplitOptions.RemoveEmptyEntries))
{
if (mapping.Contains(":"))
{
var claim = claimsPrincipal.Claims.FirstOrDefault(item => item.Type == mapping.Split(":")[0]);
if (claim != null && !string.IsNullOrEmpty(claim.Value))
{
var profile = profiles.FirstOrDefault(item => item.Name == mapping.Split(":")[1]);
if (profile != null)
{
var setting = _settings.GetSetting(EntityNames.User, user.UserId, profile.Name);
if (setting != null)
{
setting.SettingValue = claim.Value;
_settings.UpdateSetting(setting);
}
else
{
setting = new Setting { EntityName = EntityNames.User, EntityId = user.UserId, SettingName = profile.Name, SettingValue = claim.Value, IsPrivate = profile.IsPrivate };
_settings.AddSetting(setting);
}
}
}
}
}
}
_logger.Log(LogLevel.Information, "ExternalLogin", Enums.LogFunction.Security, "External User Login Successful For {Username} Using Provider {Provider}", user.Username, providerName);
}
}

View File

@ -4,14 +4,10 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Oqtane.Extensions;
using Oqtane.Models;
using Oqtane.Modules;
using Oqtane.Modules.Admin.Roles;
using Oqtane.Modules.Admin.Users;
using Oqtane.Shared;
namespace Oqtane.Repository
@ -85,7 +81,7 @@ namespace Oqtane.Repository
if (permissions.Count == 0)
{
// no module definition permissions exist for this site
moduledefinition.PermissionList = ClonePermissions(moduledefinition.PermissionList);
moduledefinition.PermissionList = ClonePermissions(siteId, moduledefinition.PermissionList);
_permissions.UpdatePermissions(siteId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, moduledefinition.PermissionList);
}
else
@ -97,7 +93,7 @@ namespace Oqtane.Repository
else
{
// permissions for module definition do not exist for this site
moduledefinition.PermissionList = ClonePermissions(moduledefinition.PermissionList);
moduledefinition.PermissionList = ClonePermissions(siteId, moduledefinition.PermissionList);
_permissions.UpdatePermissions(siteId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, moduledefinition.PermissionList);
}
}
@ -239,6 +235,16 @@ namespace Oqtane.Repository
moduledefinition.ControlTypeTemplate = modulecontroltype.Namespace + "." + Constants.ActionToken + ", " + modulecontroltype.Assembly.GetName().Name;
moduledefinition.AssemblyName = assembly.GetName().Name;
moduledefinition.IsPortable = false;
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType))
{
Type servertype = Type.GetType(moduledefinition.ServerManagerType);
if (servertype != null && servertype.GetInterface("IPortable") != null)
{
moduledefinition.IsPortable = true;
}
}
if (string.IsNullOrEmpty(moduledefinition.Categories))
{
moduledefinition.Categories = "Common";
@ -283,17 +289,18 @@ namespace Oqtane.Repository
return moduledefinitions;
}
private List<Permission> ClonePermissions(List<Permission> permissionList)
private List<Permission> ClonePermissions(int siteId, List<Permission> permissionList)
{
var permissions = new List<Permission>();
foreach (var p in permissionList)
{
var permission = new Permission();
permission.SiteId = p.SiteId;
permission.SiteId = siteId;
permission.EntityName = p.EntityName;
permission.EntityId = p.EntityId;
permission.PermissionName = p.PermissionName;
permission.RoleId = p.RoleId;
permission.RoleName = p.RoleName;
permission.UserId = p.UserId;
permission.IsAuthorized = p.IsAuthorized;
permissions.Add(permission);

View File

@ -30,10 +30,17 @@ namespace Oqtane.Repository
{
return _cache.GetOrCreate($"permissions:{alias.TenantId}:{siteId}:{entityName}", entry =>
{
var roles = _roles.GetRoles(siteId, true).ToList();
var permissions = _db.Permission.Where(item => item.SiteId == siteId).Where(item => item.EntityName == entityName).ToList();
foreach (var permission in permissions)
{
if (permission.RoleId != null)
{
permission.RoleName = roles.Find(item => item.RoleId == permission.RoleId).Name;
}
}
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
return _db.Permission.Where(item => item.SiteId == siteId)
.Where(item => item.EntityName == entityName)
.Include(item => item.Role).ToList(); // eager load roles
return permissions;
});
}
return null;
@ -84,15 +91,14 @@ namespace Oqtane.Repository
permission.SiteId = siteId;
permission.EntityName = (string.IsNullOrEmpty(permission.EntityName)) ? entityName : permission.EntityName;
permission.EntityId = (permission.EntityName == entityName) ? entityId : -1;
if (permission.RoleId == null && permission.Role != null && !string.IsNullOrEmpty(permission.Role.Name))
if (permission.UserId == null && permission.RoleId == null && !string.IsNullOrEmpty(permission.RoleName))
{
var role = roles.FirstOrDefault(item => item.Name == permission.Role.Name);
var role = roles.FirstOrDefault(item => item.Name == permission.RoleName);
if (role != null)
{
permission.RoleId = role.RoleId;
}
}
permission.Role = null;
}
// add or update permissions
bool modified = false;
@ -112,7 +118,6 @@ namespace Oqtane.Repository
if (current.IsAuthorized != permission.IsAuthorized)
{
current.IsAuthorized = permission.IsAuthorized;
current.Role = null; // remove linked reference to Role which can cause errors in EF Core change tracking
_db.Entry(current).State = EntityState.Modified;
modified = true;
}
@ -129,7 +134,6 @@ namespace Oqtane.Repository
if (!permissions.Any(item => item.EntityName == permission.EntityName && item.PermissionName == permission.PermissionName
&& item.EntityId == permission.EntityId && item.RoleId == permission.RoleId && item.UserId == permission.UserId))
{
permission.Role = null; // remove linked reference to Role which can cause errors in EF Core change tracking
_db.Permission.Remove(permission);
modified = true;
}

View File

@ -52,14 +52,9 @@ namespace Oqtane.Security
return IsAuthorized(principal, permissionName, _permissions.GetPermissions(siteId, entityName, entityId, permissionName).ToList());
}
public bool IsAuthorized(ClaimsPrincipal principal, string permissionName, List<Permission> permissions)
public bool IsAuthorized(ClaimsPrincipal principal, string permissionName, List<Permission> permissionList)
{
return UserSecurity.IsAuthorized(GetUser(principal), permissionName, permissions);
}
public bool IsAuthorized(ClaimsPrincipal principal, string permissionName, string permissions)
{
return UserSecurity.IsAuthorized(GetUser(principal), permissionName, JsonSerializer.Deserialize<List<Permission>>(permissions));
return UserSecurity.IsAuthorized(GetUser(principal), permissionName, permissionList);
}
public User GetUser(ClaimsPrincipal principal)
@ -106,5 +101,11 @@ namespace Oqtane.Security
{
return IsAuthorized(principal, permissionName, _permissions.GetPermissions(_accessor.HttpContext.GetAlias().SiteId, entityName, entityId, permissionName).ToList());
}
[Obsolete("IsAuthorized(ClaimsPrincipal principal, string permissionName, string permissions) is deprecated. Use IsAuthorized(ClaimsPrincipal principal, string permissionName, List<Permission> permissionList) instead", false)]
public bool IsAuthorized(ClaimsPrincipal principal, string permissionName, string permissions)
{
return UserSecurity.IsAuthorized(GetUser(principal), permissionName, JsonSerializer.Deserialize<List<Permission>>(permissions));
}
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Oqtane.Models
{
@ -85,18 +86,19 @@ namespace Oqtane.Models
[NotMapped]
public bool HasChildren { get; set; }
#region Deprecated Properties
[Obsolete("The Permissions property is deprecated. Use PermissionList instead", false)]
[NotMapped]
[JsonIgnore] // exclude from API payload
public string Permissions
{
get
{
return JsonSerializer.Serialize(PermissionList);
}
set
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
}
}
#endregion
}
}

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Oqtane.Models
{
@ -109,18 +110,19 @@ namespace Oqtane.Models
#endregion
#region Deprecated Properties
[Obsolete("The Permissions property is deprecated. Use PermissionList instead", false)]
[NotMapped]
[JsonIgnore] // exclude from API payload
public string Permissions
{
get
{
return JsonSerializer.Serialize(PermissionList);
}
set
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
}
}
#endregion
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;
using System.Text.Json.Serialization;
using Oqtane.Documentation;
namespace Oqtane.Models
@ -68,55 +69,75 @@ namespace Oqtane.Models
// additional IModule properties
[NotMapped]
public string Owner { get; set; }
[NotMapped]
public string Url { get; set; }
[NotMapped]
public string Contact { get; set; }
[NotMapped]
public string License { get; set; }
[NotMapped]
public string Runtimes { get; set; }
[NotMapped]
public string Dependencies { get; set; }
[NotMapped]
public string PermissionNames { get; set; }
[NotMapped]
public string ServerManagerType { get; set; }
[NotMapped]
public string ControlTypeRoutes { get; set; }
[NotMapped]
public string ReleaseVersions { get; set; }
[NotMapped]
public string DefaultAction { get; set; }
[NotMapped]
public string SettingsType { get; set; } // added in 2.0.2
[NotMapped]
public string PackageName { get; set; } // added in 2.1.0
// internal properties
[NotMapped]
public int SiteId { get; set; }
[NotMapped]
public string ControlTypeTemplate { get; set; }
[NotMapped]
public string AssemblyName { get; set; }
[NotMapped]
public List<Permission> PermissionList { get; set; }
[NotMapped]
public string Template { get; set; }
[NotMapped]
public bool IsPortable { get; set; }
#region Deprecated Properties
[Obsolete("The Permissions property is deprecated. Use PermissionList instead", false)]
[NotMapped]
[JsonIgnore] // exclude from API payload
public string Permissions
{
get
{
return JsonSerializer.Serialize(PermissionList);
}
set
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
}
}
#endregion
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Oqtane.Models
{
@ -115,26 +116,24 @@ namespace Oqtane.Models
#region Deprecated Properties
[Obsolete("This property is deprecated", false)]
[Obsolete("The EditMode property is deprecated", false)]
[NotMapped]
public bool EditMode { get; set; }
[Obsolete("This property is deprecated", false)]
[Obsolete("The LayoutType property is deprecated", false)]
[NotMapped]
public string LayoutType { get; set; }
[Obsolete("The Permissions property is deprecated. Use PermissionList instead", false)]
[NotMapped]
[JsonIgnore] // exclude from API payload
public string Permissions {
get
{
return JsonSerializer.Serialize(PermissionList);
}
set
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
}
}
#endregion
}
}

View File

@ -1,3 +1,7 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using System;
namespace Oqtane.Models
{
/// <summary>
@ -17,47 +21,41 @@ namespace Oqtane.Models
public int SiteId { get; set; }
/// <summary>
/// Name of the Entity these permissions apply to.
/// Name of the Entity these permissions apply to (ie. Module )
/// </summary>
public string EntityName { get; set; }
/// <summary>
/// ID of the Entity these permissions apply to.
/// ID of the Entity these permissions apply to (ie. a ModuleId). A value of -1 indicates the permission applies to all EntityNames regardless of ID (ie. API permissions)
/// </summary>
public int EntityId { get; set; }
/// <summary>
/// What this permission is called.
/// TODO: todoc - must clarify what exactly this means, I assume any module can give it's own names for Permissions
/// Name of the permission (ie. View)
/// </summary>
public string PermissionName { get; set; }
/// <summary>
/// <see cref="Role"/> this permission applies to. So if all users in the Role _Customers_ have this permission, then it would reference that Role.
/// If null, then the permission doesn't target a role but probably a <see cref="User"/> (see <see cref="UserId"/>).
/// <see cref="Role"/> this permission applies to. If null then this is a <see cref="User"/> permission.
/// </summary>
public int? RoleId { get; set; }
/// <summary>
/// The role name associated to the RoleId.
/// </summary>
[NotMapped]
public string RoleName { get; set; }
/// <summary>
/// <see cref="User"/> this permission applies to.
/// If null, then the permission doesn't target a User but probably a <see cref="Role"/> (see <see cref="RoleId"/>).
/// <see cref="User"/> this permission applies to. If null then this is a <see cref="Role"/> permission.
/// </summary>
public int? UserId { get; set; }
/// <summary>
/// Determines if Authorization is sufficient to receive this permission.
/// The type of permission (ie. grant = true, deny = false)
/// </summary>
public bool IsAuthorized { get; set; }
/// <summary>
/// Reference to the <see cref="Role"/> based on the <see cref="RoleId"/> - can be nullable.
/// </summary>
/// <remarks>
/// It's not certain if this will always be populated. TODO: todoc/verify
/// </remarks>
public Role Role { get; set; }
public Permission()
{
}
@ -90,17 +88,22 @@ namespace Oqtane.Models
PermissionName = permissionName;
if (!string.IsNullOrEmpty(roleName))
{
Role = new Role { Name = roleName };
RoleId = null;
RoleName = roleName;
UserId = null;
}
else
{
Role = null;
RoleId = null;
RoleName = null;
UserId = userId;
}
IsAuthorized = isAuthorized;
}
[Obsolete("The Role property is deprecated", false)]
[NotMapped]
[JsonIgnore] // exclude from API payload
public Role Role { get; set; }
}
}

View File

@ -33,10 +33,6 @@ namespace Oqtane.Models
{
return JsonSerializer.Serialize(PermissionList);
}
set
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(PagePermissions);
}
}
}
@ -55,10 +51,6 @@ namespace Oqtane.Models
{
return JsonSerializer.Serialize(PermissionList);
}
set
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(ModulePermissions);
}
}
}
}

View File

@ -20,56 +20,51 @@ namespace Oqtane.Security
return IsAuthorized(user, permissions);
}
public static bool IsAuthorized(User user, string permissionName, List<Permission> permissions)
public static bool IsAuthorized(User user, string permissionName, List<Permission> permissionList)
{
return IsAuthorized(user, permissions.Where(item => item.PermissionName == permissionName).ToList());
return IsAuthorized(user, permissionList.Where(item => item.PermissionName == permissionName).ToList());
}
public static bool IsAuthorized(User user, string permissionName, string permissions)
{
return IsAuthorized(user, JsonSerializer.Deserialize<List<Permission>>(permissions).Where(item => item.PermissionName == permissionName).ToList());
}
public static bool IsAuthorized(User user, List<Permission> permissions)
public static bool IsAuthorized(User user, List<Permission> permissionList)
{
bool authorized = false;
if (permissions != null && permissions.Any())
if (permissionList != null && permissionList.Any())
{
if (user == null)
{
authorized = IsAuthorized(-1, "", permissions); // user is not authenticated but may have access to resource
authorized = IsAuthorized(-1, "", permissionList); // user is not authenticated but may have access to resource
}
else
{
authorized = IsAuthorized(user.UserId, user.Roles, permissions);
authorized = IsAuthorized(user.UserId, user.Roles, permissionList);
}
}
return authorized;
}
private static bool IsAuthorized(int userId, string roles, List<Permission> permissions)
private static bool IsAuthorized(int userId, string roles, List<Permission> permissionList)
{
bool isAuthorized = false;
if (permissions != null && permissions.Any())
if (permissionList != null && permissionList.Any())
{
// check if denied first
isAuthorized = !permissions.Where(item => !item.IsAuthorized && (
(item.Role != null && (
(item.Role.Name == RoleNames.Everyone) ||
(item.Role.Name == RoleNames.Unauthenticated && userId == -1) ||
roles.Split(';', StringSplitOptions.RemoveEmptyEntries).Contains(item.Role.Name))) ||
isAuthorized = !permissionList.Where(item => !item.IsAuthorized && (
(item.UserId == null && (
(item.RoleName == RoleNames.Everyone) ||
(item.RoleName == RoleNames.Unauthenticated && userId == -1) ||
roles.Split(';', StringSplitOptions.RemoveEmptyEntries).Contains(item.RoleName))) ||
(item.UserId != null && item.UserId.Value == userId))).Any();
if (isAuthorized)
{
// then check if authorized
isAuthorized = permissions.Where(item => item.IsAuthorized && (
(item.Role != null && (
(item.Role.Name == RoleNames.Everyone) ||
(item.Role.Name == RoleNames.Unauthenticated && userId == -1) ||
roles.Split(';', StringSplitOptions.RemoveEmptyEntries).Contains(item.Role.Name))) ||
isAuthorized = permissionList.Where(item => item.IsAuthorized && (
(item.UserId == null && (
(item.RoleName == RoleNames.Everyone) ||
(item.RoleName == RoleNames.Unauthenticated && userId == -1) ||
roles.Split(';', StringSplitOptions.RemoveEmptyEntries).Contains(item.RoleName))) ||
(item.UserId != null && item.UserId.Value == userId))).Any();
}
}
@ -79,7 +74,7 @@ namespace Oqtane.Security
public static bool ContainsRole(List<Permission> permissions, string permissionName, string roleName)
{
return permissions.Any(item => item.PermissionName == permissionName && item.Role.Name == roleName);
return permissions.Any(item => item.PermissionName == permissionName && item.RoleName == roleName);
}
public static bool ContainsUser(List<Permission> permissions, string permissionName, int userId)
@ -123,5 +118,11 @@ namespace Oqtane.Security
}
return identity;
}
[Obsolete("IsAuthorized(User user, string permissionName, string permissions) is deprecated. Use IsAuthorized(User user, string permissionName, List<Permission> permissionList) instead", false)]
public static bool IsAuthorized(User user, string permissionName, string permissions)
{
return IsAuthorized(user, JsonSerializer.Deserialize<List<Permission>>(permissions).Where(item => item.PermissionName == permissionName).ToList());
}
}
}