Browse Source

More OIDC options.

pull/387/head
Sebastian Stehle 7 years ago
parent
commit
dc5a684265
  1. 6
      src/Squidex.Infrastructure/Commands/ReadonlyCommandMiddleware.cs
  2. 6
      src/Squidex.Web/Pipeline/EnforceHttpsMiddleware.cs
  3. 8
      src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs
  4. 10
      src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs
  5. 14
      src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs
  6. 6
      src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs
  7. 44
      src/Squidex/Config/Authentication/OidcHandler.cs
  8. 12
      src/Squidex/Config/Authentication/OidcServices.cs
  9. 12
      src/Squidex/Config/MyIdentityOptions.cs
  10. 3
      src/Squidex/appsettings.json

6
src/Squidex.Infrastructure/Commands/ReadonlyCommandMiddleware.cs

@ -13,18 +13,18 @@ namespace Squidex.Infrastructure.Commands
{
public sealed class ReadonlyCommandMiddleware : ICommandMiddleware
{
private readonly IOptions<ReadonlyOptions> options;
private readonly ReadonlyOptions options;
public ReadonlyCommandMiddleware(IOptions<ReadonlyOptions> options)
{
Guard.NotNull(options, nameof(options));
this.options = options;
this.options = options.Value;
}
public Task HandleAsync(CommandContext context, Func<Task> next)
{
if (options.Value.IsReadonly)
if (options.IsReadonly)
{
throw new DomainException("Application is in readonly mode at the moment.");
}

6
src/Squidex.Web/Pipeline/EnforceHttpsMiddleware.cs

@ -14,16 +14,16 @@ namespace Squidex.Web.Pipeline
{
public sealed class EnforceHttpsMiddleware : IMiddleware
{
private readonly IOptions<UrlsOptions> urls;
private readonly UrlsOptions urls;
public EnforceHttpsMiddleware(IOptions<UrlsOptions> urls)
{
this.urls = urls;
this.urls = urls.Value;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (!urls.Value.EnforceHTTPS)
if (!urls.EnforceHTTPS)
{
await next(context);
}

8
src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs

@ -37,7 +37,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
private readonly IAssetQueryService assetQuery;
private readonly IAssetUsageTracker assetStatsRepository;
private readonly IAppPlansProvider appPlansProvider;
private readonly IOptions<MyContentsControllerOptions> controllerOptions;
private readonly MyContentsControllerOptions controllerOptions;
private readonly ITagService tagService;
private readonly AssetOptions assetOptions;
@ -55,7 +55,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
this.assetQuery = assetQuery;
this.assetStatsRepository = assetStatsRepository;
this.appPlansProvider = appPlansProvider;
this.controllerOptions = controllerOptions;
this.controllerOptions = controllerOptions.Value;
this.tagService = tagService;
}
@ -110,7 +110,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
return AssetsDto.FromAssets(assets, this, app);
});
if (controllerOptions.Value.EnableSurrogateKeys && assets.Count <= controllerOptions.Value.MaxItemsForSurrogateKeys)
if (controllerOptions.EnableSurrogateKeys && assets.Count <= controllerOptions.MaxItemsForSurrogateKeys)
{
Response.Headers["Surrogate-Key"] = assets.ToSurrogateKeys();
}
@ -148,7 +148,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
return AssetDto.FromAsset(asset, this, app);
});
if (controllerOptions.Value.EnableSurrogateKeys)
if (controllerOptions.EnableSurrogateKeys)
{
Response.Headers["Surrogate-Key"] = asset.ToSurrogateKey();
}

10
src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs

@ -25,7 +25,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
{
public sealed class ContentsController : ApiController
{
private readonly IOptions<MyContentsControllerOptions> controllerOptions;
private readonly MyContentsControllerOptions controllerOptions;
private readonly IContentQueryService contentQuery;
private readonly IContentWorkflow contentWorkflow;
private readonly IGraphQLService graphQl;
@ -39,7 +39,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
{
this.contentQuery = contentQuery;
this.contentWorkflow = contentWorkflow;
this.controllerOptions = controllerOptions;
this.controllerOptions = controllerOptions.Value;
this.graphQl = graphQl;
}
@ -205,7 +205,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
var response = ContentDto.FromContent(Context, content, this);
if (controllerOptions.Value.EnableSurrogateKeys)
if (controllerOptions.EnableSurrogateKeys)
{
Response.Headers["Surrogate-Key"] = content.ToSurrogateKey();
}
@ -240,7 +240,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
var response = ContentDto.FromContent(Context, content, this);
if (controllerOptions.Value.EnableSurrogateKeys)
if (controllerOptions.EnableSurrogateKeys)
{
Response.Headers["Surrogate-Key"] = content.ToSurrogateKey();
}
@ -446,7 +446,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
private bool ShouldProvideSurrogateKeys(IReadOnlyList<IContentEntity> response)
{
return controllerOptions.Value.EnableSurrogateKeys && response.Count <= controllerOptions.Value.MaxItemsForSurrogateKeys;
return controllerOptions.EnableSurrogateKeys && response.Count <= controllerOptions.MaxItemsForSurrogateKeys;
}
}
}

14
src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs

@ -36,7 +36,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
private readonly UserManager<IdentityUser> userManager;
private readonly IUserFactory userFactory;
private readonly IUserEvents userEvents;
private readonly IOptions<MyIdentityOptions> identityOptions;
private readonly MyIdentityOptions identityOptions;
private readonly ISemanticLog log;
private readonly IIdentityServerInteractionService interactions;
@ -54,7 +54,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
this.userManager = userManager;
this.userFactory = userFactory;
this.interactions = interactions;
this.identityOptions = identityOptions;
this.identityOptions = identityOptions.Value;
this.signInManager = signInManager;
}
@ -97,7 +97,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
[Route("account/consent/")]
public IActionResult Consent(string returnUrl = null)
{
return View(new ConsentVM { PrivacyUrl = identityOptions.Value.PrivacyUrl, ReturnUrl = returnUrl });
return View(new ConsentVM { PrivacyUrl = identityOptions.PrivacyUrl, ReturnUrl = returnUrl });
}
[HttpPost]
@ -116,7 +116,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
if (!ModelState.IsValid)
{
var vm = new ConsentVM { PrivacyUrl = identityOptions.Value.PrivacyUrl, ReturnUrl = returnUrl };
var vm = new ConsentVM { PrivacyUrl = identityOptions.PrivacyUrl, ReturnUrl = returnUrl };
return View(vm);
}
@ -194,7 +194,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
private async Task<IActionResult> LoginViewAsync(string returnUrl, bool isLogin, bool isFailed)
{
var allowPasswordAuth = identityOptions.Value.AllowPasswordAuth;
var allowPasswordAuth = identityOptions.AllowPasswordAuth;
var externalProviders = await signInManager.GetExternalProvidersAsync();
@ -298,7 +298,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
{
return RedirectToAction(nameof(Login));
}
else if (user != null && !user.HasConsent())
else if (user != null && !user.HasConsent() && !identityOptions.NoConsent)
{
return RedirectToAction(nameof(Consent), new { returnUrl });
}
@ -327,7 +327,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
private Task<bool> LockAsync(UserWithClaims user, bool isFirst)
{
if (isFirst || !identityOptions.Value.LockAutomatically)
if (isFirst || !identityOptions.LockAutomatically)
{
return TaskHelper.True;
}

6
src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs

@ -32,7 +32,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Profile
private readonly UserManager<IdentityUser> userManager;
private readonly IUserPictureStore userPictureStore;
private readonly IAssetThumbnailGenerator assetThumbnailGenerator;
private readonly IOptions<MyIdentityOptions> identityOptions;
private readonly MyIdentityOptions identityOptions;
public ProfileController(
SignInManager<IdentityUser> signInManager,
@ -42,7 +42,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Profile
IOptions<MyIdentityOptions> identityOptions)
{
this.signInManager = signInManager;
this.identityOptions = identityOptions;
this.identityOptions = identityOptions.Value;
this.userManager = userManager;
this.userPictureStore = userPictureStore;
this.assetThumbnailGenerator = assetThumbnailGenerator;
@ -198,7 +198,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Profile
DisplayName = user.DisplayName(),
IsHidden = user.IsHidden(),
HasPassword = taskForPassword.Result,
HasPasswordAuth = identityOptions.Value.AllowPasswordAuth,
HasPasswordAuth = identityOptions.AllowPasswordAuth,
SuccessMessage = successMessage
};

44
src/Squidex/Config/Authentication/OidcHandler.cs

@ -0,0 +1,44 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Squidex.Shared.Identity;
namespace Squidex.Config.Authentication
{
public sealed class OidcHandler : OpenIdConnectEvents
{
private readonly MyIdentityOptions options;
public OidcHandler(MyIdentityOptions options )
{
this.options = options;
}
public override Task TokenValidated(TokenValidatedContext context)
{
var identity = (ClaimsIdentity)context.Principal.Identity;
if (!string.IsNullOrWhiteSpace(options.OidcRoleClaimType) && options.OidcRoleMapping?.Count >= 0)
{
var role = identity.FindFirst(x => x.Type == options.OidcRoleClaimType)?.Value;
if (!string.IsNullOrWhiteSpace(role) && options.OidcRoleMapping.TryGetValue(role, out var permissions) && permissions != null)
{
foreach (var permission in permissions)
{
identity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission));
}
}
}
return base.TokenValidated(context);
}
}
}

12
src/Squidex/Config/Authentication/OidcServices.cs

@ -8,6 +8,7 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.Tasks;
using Squidex.Web;
namespace Squidex.Config.Authentication
@ -25,9 +26,16 @@ namespace Squidex.Config.Authentication
options.Authority = identityOptions.OidcAuthority;
options.ClientId = identityOptions.OidcClient;
options.ClientSecret = identityOptions.OidcSecret;
options.Scope.Add(Constants.EmailScope);
options.Scope.Add(Constants.PermissionsScope);
options.RequireHttpsMetadata = false;
options.Events = new OidcHandler(identityOptions);
if (identityOptions.OidcScopes != null)
{
foreach (var scope in identityOptions.OidcScopes)
{
options.Scope.Add(scope);
}
}
});
}

12
src/Squidex/Config/MyIdentityOptions.cs

@ -5,6 +5,8 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Config
{
public sealed class MyIdentityOptions
@ -37,6 +39,12 @@ namespace Squidex.Config
public string OidcAuthority { get; set; }
public string OidcRoleClaimType { get; set; }
public string[] OidcScopes { get; set; }
public Dictionary<string, string[]> OidcRoleMapping { get; set; }
public string AuthorityUrl { get; set; }
public string PrivacyUrl { get; set; }
@ -47,6 +55,8 @@ namespace Squidex.Config
public bool LockAutomatically { get; set; }
public bool NoConsent { get; set; }
public bool IsAdminConfigured()
{
return !string.IsNullOrWhiteSpace(AdminEmail) && !string.IsNullOrWhiteSpace(AdminPassword);
@ -59,7 +69,7 @@ namespace Squidex.Config
public bool IsOidcConfigured()
{
return !string.IsNullOrWhiteSpace(OidcAuthority) && !string.IsNullOrWhiteSpace(OidcClient) && !string.IsNullOrWhiteSpace(OidcSecret);
return !string.IsNullOrWhiteSpace(OidcAuthority) && !string.IsNullOrWhiteSpace(OidcClient);
}
public bool IsGithubAuthConfigured()

3
src/Squidex/appsettings.json

@ -440,6 +440,9 @@
"oidcAuthority": "",
"oidcClient": "",
"oidcSecret": "",
"oidcScopes": [
"email"
],
/*
* Lock new users automatically, the administrator must unlock them.
*/

Loading…
Cancel
Save