mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
8.9 KiB
237 lines
8.9 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using Microsoft.Extensions.Options;
|
|
using OpenIddict.Abstractions;
|
|
using Squidex.Config;
|
|
using Squidex.Domain.Apps.Core.Apps;
|
|
using Squidex.Domain.Apps.Entities;
|
|
using Squidex.Domain.Users;
|
|
using Squidex.Domain.Users.InMemory;
|
|
using Squidex.Hosting;
|
|
using Squidex.Infrastructure;
|
|
using Squidex.Shared.Identity;
|
|
using Squidex.Shared.Users;
|
|
using Squidex.Web;
|
|
using static OpenIddict.Abstractions.OpenIddictConstants;
|
|
|
|
namespace Squidex.Areas.IdentityServer.Config
|
|
{
|
|
public class DynamicApplicationStore : InMemoryApplicationStore
|
|
{
|
|
private readonly IServiceProvider serviceProvider;
|
|
|
|
public DynamicApplicationStore(IServiceProvider serviceProvider)
|
|
: base(CreateStaticClients(serviceProvider))
|
|
{
|
|
this.serviceProvider = serviceProvider;
|
|
}
|
|
|
|
public override async ValueTask<ImmutableApplication?> FindByIdAsync(string identifier,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var application = await base.FindByIdAsync(identifier, cancellationToken);
|
|
|
|
if (application == null)
|
|
{
|
|
application = await GetDynamicAsync(identifier);
|
|
}
|
|
|
|
return application;
|
|
}
|
|
|
|
public override async ValueTask<ImmutableApplication?> FindByClientIdAsync(string identifier,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var application = await base.FindByClientIdAsync(identifier, cancellationToken);
|
|
|
|
if (application == null)
|
|
{
|
|
application = await GetDynamicAsync(identifier);
|
|
}
|
|
|
|
return application;
|
|
}
|
|
|
|
private async Task<ImmutableApplication?> GetDynamicAsync(string clientId)
|
|
{
|
|
var (appName, appClientId) = clientId.GetClientParts();
|
|
|
|
var appProvider = serviceProvider.GetRequiredService<IAppProvider>();
|
|
|
|
if (!string.IsNullOrWhiteSpace(appName) && !string.IsNullOrWhiteSpace(appClientId))
|
|
{
|
|
var app = await appProvider.GetAppAsync(appName, true);
|
|
|
|
var appClient = app?.Clients.GetValueOrDefault(appClientId);
|
|
|
|
if (appClient != null)
|
|
{
|
|
return CreateClientFromApp(clientId, appClient);
|
|
}
|
|
}
|
|
|
|
await using (var scope = serviceProvider.CreateAsyncScope())
|
|
{
|
|
var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
|
|
|
|
var user = await userService.FindByIdAsync(clientId);
|
|
|
|
if (user == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var secret = user.Claims.ClientSecret();
|
|
|
|
if (!string.IsNullOrWhiteSpace(secret))
|
|
{
|
|
return CreateClientFromUser(user, secret);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static ImmutableApplication CreateClientFromUser(IUser user, string secret)
|
|
{
|
|
return new ImmutableApplication(user.Id, new OpenIddictApplicationDescriptor
|
|
{
|
|
DisplayName = $"{user.Email} Client",
|
|
ClientId = user.Id,
|
|
ClientSecret = secret,
|
|
Permissions =
|
|
{
|
|
Permissions.Endpoints.Token,
|
|
Permissions.GrantTypes.ClientCredentials,
|
|
Permissions.ResponseTypes.Token,
|
|
Permissions.Scopes.Email,
|
|
Permissions.Scopes.Profile,
|
|
Permissions.Scopes.Roles,
|
|
Permissions.Prefixes.Scope + Constants.ScopeApi,
|
|
Permissions.Prefixes.Scope + Constants.ScopePermissions
|
|
}
|
|
}.CopyClaims(user));
|
|
}
|
|
|
|
private static ImmutableApplication CreateClientFromApp(string id, AppClient appClient)
|
|
{
|
|
return new ImmutableApplication(id, new OpenIddictApplicationDescriptor
|
|
{
|
|
DisplayName = id,
|
|
ClientId = id,
|
|
ClientSecret = appClient.Secret,
|
|
Permissions =
|
|
{
|
|
Permissions.Endpoints.Token,
|
|
Permissions.GrantTypes.ClientCredentials,
|
|
Permissions.ResponseTypes.Token,
|
|
Permissions.Scopes.Email,
|
|
Permissions.Scopes.Profile,
|
|
Permissions.Scopes.Roles,
|
|
Permissions.Prefixes.Scope + Constants.ScopeApi,
|
|
Permissions.Prefixes.Scope + Constants.ScopePermissions
|
|
}
|
|
});
|
|
}
|
|
|
|
private static IEnumerable<(string, OpenIddictApplicationDescriptor)> CreateStaticClients(IServiceProvider serviceProvider)
|
|
{
|
|
var identityOptions = serviceProvider.GetRequiredService<IOptions<MyIdentityOptions>>().Value;
|
|
|
|
var urlGenerator = serviceProvider.GetRequiredService<IUrlGenerator>();
|
|
|
|
var frontendId = Constants.ClientFrontendId;
|
|
|
|
yield return (frontendId, new OpenIddictApplicationDescriptor
|
|
{
|
|
DisplayName = "Frontend Client",
|
|
ClientId = frontendId,
|
|
ClientSecret = null,
|
|
RedirectUris =
|
|
{
|
|
new Uri(urlGenerator.BuildUrl("login;")),
|
|
new Uri(urlGenerator.BuildUrl("client-callback-silent.html", false)),
|
|
new Uri(urlGenerator.BuildUrl("client-callback-popup.html", false))
|
|
},
|
|
PostLogoutRedirectUris =
|
|
{
|
|
new Uri(urlGenerator.BuildUrl("logout", false))
|
|
},
|
|
Permissions =
|
|
{
|
|
Permissions.Endpoints.Authorization,
|
|
Permissions.Endpoints.Logout,
|
|
Permissions.Endpoints.Token,
|
|
Permissions.GrantTypes.AuthorizationCode,
|
|
Permissions.GrantTypes.RefreshToken,
|
|
Permissions.ResponseTypes.Code,
|
|
Permissions.Scopes.Email,
|
|
Permissions.Scopes.Profile,
|
|
Permissions.Scopes.Roles,
|
|
Permissions.Prefixes.Scope + Constants.ScopeApi,
|
|
Permissions.Prefixes.Scope + Constants.ScopePermissions
|
|
},
|
|
Type = ClientTypes.Public
|
|
});
|
|
|
|
var internalClientId = Constants.ClientInternalId;
|
|
|
|
yield return (internalClientId, new OpenIddictApplicationDescriptor
|
|
{
|
|
DisplayName = "Internal Client",
|
|
ClientId = internalClientId,
|
|
ClientSecret = Constants.ClientInternalSecret,
|
|
RedirectUris =
|
|
{
|
|
new Uri(urlGenerator.BuildUrl("/signin-internal", false))
|
|
},
|
|
Permissions =
|
|
{
|
|
Permissions.Endpoints.Authorization,
|
|
Permissions.Endpoints.Logout,
|
|
Permissions.Endpoints.Token,
|
|
Permissions.GrantTypes.Implicit,
|
|
Permissions.ResponseTypes.IdToken,
|
|
Permissions.ResponseTypes.IdTokenToken,
|
|
Permissions.ResponseTypes.Token,
|
|
Permissions.Scopes.Email,
|
|
Permissions.Scopes.Profile,
|
|
Permissions.Scopes.Roles,
|
|
Permissions.Prefixes.Scope + Constants.ScopeApi,
|
|
Permissions.Prefixes.Scope + Constants.ScopePermissions
|
|
},
|
|
Type = ClientTypes.Public
|
|
});
|
|
|
|
if (!identityOptions.IsAdminClientConfigured())
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
var adminClientId = identityOptions.AdminClientId;
|
|
|
|
yield return (adminClientId, new OpenIddictApplicationDescriptor
|
|
{
|
|
DisplayName = "Admin Client",
|
|
ClientId = adminClientId,
|
|
ClientSecret = identityOptions.AdminClientSecret,
|
|
Permissions =
|
|
{
|
|
Permissions.Endpoints.Token,
|
|
Permissions.GrantTypes.ClientCredentials,
|
|
Permissions.ResponseTypes.Token,
|
|
Permissions.Scopes.Email,
|
|
Permissions.Scopes.Profile,
|
|
Permissions.Scopes.Roles,
|
|
Permissions.Prefixes.Scope + Constants.ScopeApi,
|
|
Permissions.Prefixes.Scope + Constants.ScopePermissions
|
|
}
|
|
}.SetAdmin());
|
|
}
|
|
}
|
|
}
|
|
|