Browse Source

Authorization fixed

pull/147/merge
Sebastian Stehle 8 years ago
parent
commit
d27929dea0
  1. 3
      src/Squidex/Controllers/ContentApi/ContentSwaggerController.cs
  2. 5
      src/Squidex/Pipeline/AppApiAttribute.cs
  3. 99
      src/Squidex/Pipeline/AppApiFilter.cs
  4. 107
      src/Squidex/Pipeline/AppPermissionAttribute.cs
  5. 6
      src/Squidex/Pipeline/MustBeAppDeveloperAttribute.cs
  6. 6
      src/Squidex/Pipeline/MustBeAppEditorAttribute.cs
  7. 6
      src/Squidex/Pipeline/MustBeAppOwnerAttribute.cs
  8. 6
      src/Squidex/Pipeline/MustBeAppReaderAttribute.cs
  9. 2
      src/Squidex/app/shell/pages/app/left-menu.component.html

3
src/Squidex/Controllers/ContentApi/ContentSwaggerController.cs

@ -16,9 +16,8 @@ using Squidex.Pipeline;
namespace Squidex.Controllers.ContentApi
{
[ApiAuthorize]
[ApiExceptionFilter]
[AppApi(false)]
[AppApi]
[SwaggerIgnore]
public sealed class ContentSwaggerController : ControllerBase
{

5
src/Squidex/Pipeline/AppApiAttribute.cs

@ -12,12 +12,9 @@ namespace Squidex.Pipeline
{
public sealed class AppApiAttribute : ServiceFilterAttribute
{
public bool CheckPermissions { get; }
public AppApiAttribute(bool checkPermissions = true)
public AppApiAttribute()
: base(typeof(AppApiFilter))
{
CheckPermissions = checkPermissions;
}
}
}

99
src/Squidex/Pipeline/AppApiFilter.cs

@ -7,48 +7,21 @@
// ==========================================================================
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Apps.Services;
using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.UsageTracking;
using Squidex.Shared.Identity;
namespace Squidex.Pipeline
{
public sealed class AppApiFilter : AuthorizeFilter, IFilterContainer
public sealed class AppApiFilter : IAsyncActionFilter
{
private static readonly AuthorizationPolicy DefaultPolicy =
new AuthorizationPolicyBuilder()
.AddRequirements(new DenyAnonymousAuthorizationRequirement())
.AddAuthenticationSchemes(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.Build();
private readonly IAppProvider appProvider;
private readonly IAppPlansProvider appPlanProvider;
private readonly IUsageTracker usageTracker;
IFilterMetadata IFilterContainer.FilterDefinition { get; set; }
public AppApiAttribute FilterDefinition
{
get
{
return (AppApiAttribute)((IFilterContainer)this).FilterDefinition;
}
}
public AppApiFilter(IAppProvider appProvider, IAppPlansProvider appPlanProvider, IUsageTracker usageTracker)
: base(DefaultPolicy)
{
this.appProvider = appProvider;
this.appPlanProvider = appPlanProvider;
@ -56,10 +29,8 @@ namespace Squidex.Pipeline
this.usageTracker = usageTracker;
}
public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
await base.OnAuthorizationAsync(context);
var appName = context.RouteData.Values["app"]?.ToString();
if (!string.IsNullOrWhiteSpace(appName))
@ -72,24 +43,6 @@ namespace Squidex.Pipeline
return;
}
if (!FilterDefinition.CheckPermissions)
{
context.HttpContext.Features.Set<IAppFeature>(new AppFeature(app));
return;
}
var user = context.HttpContext.User;
var permission =
FindByOpenIdSubject(app, user) ??
FindByOpenIdClient(app, user);
if (permission == null)
{
context.Result = new NotFoundResult();
return;
}
var plan = appPlanProvider.GetPlanForApp(app);
var usage = await usageTracker.GetMonthlyCalls(app.Id.ToString(), DateTime.Today);
@ -100,56 +53,10 @@ namespace Squidex.Pipeline
return;
}
var defaultIdentity = context.HttpContext.User.Identities.First();
switch (permission.Value)
{
case AppPermission.Owner:
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppOwner));
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppDeveloper));
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppEditor));
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppReader));
break;
case AppPermission.Developer:
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppDeveloper));
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppEditor));
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppReader));
break;
case AppPermission.Editor:
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppEditor));
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppReader));
break;
case AppPermission.Reader:
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, SquidexRoles.AppReader));
break;
}
context.HttpContext.Features.Set<IAppFeature>(new AppFeature(app));
}
}
private static AppPermission? FindByOpenIdClient(IAppEntity app, ClaimsPrincipal user)
{
var clientId = user.GetClientId();
if (clientId != null && app.Clients.TryGetValue(clientId, out var client))
{
return client.Permission.ToAppPermission();
}
return null;
}
private static AppPermission? FindByOpenIdSubject(IAppEntity app, ClaimsPrincipal user)
{
var subjectId = user.FindFirst(OpenIdClaims.Subject)?.Value;
if (subjectId != null && app.Contributors.TryGetValue(subjectId, out var contributor))
{
return contributor.Permission.ToAppPermission();
}
return null;
await next();
}
}
}

107
src/Squidex/Pipeline/AppPermissionAttribute.cs

@ -0,0 +1,107 @@
// ==========================================================================
// AppPermissionAttribute.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Infrastructure.Security;
using Squidex.Shared.Identity;
namespace Squidex.Pipeline
{
public abstract class AppPermissionAttribute : ActionFilterAttribute
{
private readonly AppPermission requestedPermission;
protected AppPermissionAttribute(AppPermission requestedPermission)
{
this.requestedPermission = requestedPermission;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
var app = context.HttpContext.Features.Get<IAppFeature>()?.App;
if (app != null)
{
var user = context.HttpContext.User;
var permission =
FindByOpenIdSubject(app, user) ??
FindByOpenIdClient(app, user);
if (permission == null)
{
context.Result = new NotFoundResult();
return;
}
if (permission.Value > requestedPermission)
{
context.Result = new StatusCodeResult(403);
return;
}
var defaultIdentity = context.HttpContext.User.Identities.First();
var additionalRoles = new List<string>
{
SquidexRoles.AppReader
};
if (permission.Value <= AppPermission.Editor)
{
additionalRoles.Add(SquidexRoles.AppEditor);
}
if (permission.Value <= AppPermission.Developer)
{
additionalRoles.Add(SquidexRoles.AppDeveloper);
}
if (permission.Value <= AppPermission.Owner)
{
additionalRoles.Add(SquidexRoles.AppOwner);
}
foreach (var role in additionalRoles)
{
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, role));
}
}
}
private static AppPermission? FindByOpenIdClient(IAppEntity app, ClaimsPrincipal user)
{
var clientId = user.GetClientId();
if (clientId != null && app.Clients.TryGetValue(clientId, out var client))
{
return client.Permission.ToAppPermission();
}
return null;
}
private static AppPermission? FindByOpenIdSubject(IAppEntity app, ClaimsPrincipal user)
{
var subjectId = user.FindFirst(OpenIdClaims.Subject)?.Value;
if (subjectId != null && app.Contributors.TryGetValue(subjectId, out var contributor))
{
return contributor.Permission.ToAppPermission();
}
return null;
}
}
}

6
src/Squidex/Pipeline/MustBeAppDeveloperAttribute.cs

@ -6,15 +6,15 @@
// All rights reserved.
// ==========================================================================
using Squidex.Shared.Identity;
using Squidex.Domain.Apps.Core.Apps;
namespace Squidex.Pipeline
{
public sealed class MustBeAppDeveloperAttribute : ApiAuthorizeAttribute
public sealed class MustBeAppDeveloperAttribute : AppPermissionAttribute
{
public MustBeAppDeveloperAttribute()
: base(AppPermission.Developer)
{
Roles = SquidexRoles.AppDeveloper;
}
}
}

6
src/Squidex/Pipeline/MustBeAppEditorAttribute.cs

@ -6,15 +6,15 @@
// All rights reserved.
// ==========================================================================
using Squidex.Shared.Identity;
using Squidex.Domain.Apps.Core.Apps;
namespace Squidex.Pipeline
{
public sealed class MustBeAppEditorAttribute : ApiAuthorizeAttribute
public sealed class MustBeAppEditorAttribute : AppPermissionAttribute
{
public MustBeAppEditorAttribute()
: base(AppPermission.Editor)
{
Roles = SquidexRoles.AppEditor;
}
}
}

6
src/Squidex/Pipeline/MustBeAppOwnerAttribute.cs

@ -6,15 +6,15 @@
// All rights reserved.
// ==========================================================================
using Squidex.Shared.Identity;
using Squidex.Domain.Apps.Core.Apps;
namespace Squidex.Pipeline
{
public sealed class MustBeAppOwnerAttribute : ApiAuthorizeAttribute
public sealed class MustBeAppOwnerAttribute : AppPermissionAttribute
{
public MustBeAppOwnerAttribute()
: base(AppPermission.Owner)
{
Roles = SquidexRoles.AppOwner;
}
}
}

6
src/Squidex/Pipeline/MustBeAppReaderAttribute.cs

@ -6,15 +6,15 @@
// All rights reserved.
// ==========================================================================
using Squidex.Shared.Identity;
using Squidex.Domain.Apps.Core.Apps;
namespace Squidex.Pipeline
{
public sealed class MustBeAppReaderAttribute : ApiAuthorizeAttribute
public sealed class MustBeAppReaderAttribute : AppPermissionAttribute
{
public MustBeAppReaderAttribute()
: base(AppPermission.Reader)
{
Roles = SquidexRoles.AppReader;
}
}
}

2
src/Squidex/app/shell/pages/app/left-menu.component.html

@ -20,7 +20,7 @@
<i class="nav-icon icon-webhooks"></i> <div class="nav-text">Webhooks</div>
</a>
</li>
<li class="nav-item" *ngIf="permission === 'Owner'">
<li class="nav-item">
<a class="nav-link" routerLink="settings" routerLinkActive="active">
<i class="nav-icon icon-settings"></i> <div class="nav-text">Settings</div>
</a>

Loading…
Cancel
Save