using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Localization; using OpenIddict.Abstractions; using Volo.Abp; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.PermissionManagement; using Volo.Abp.Uow; namespace Himp.TaskScheduling.OpenIddict; /* Creates initial data that is needed to property run the application * and make client-to-server communication possible. */ public class OpenIddictDataSeedContributor : IDataSeedContributor, ITransientDependency { private readonly IConfiguration _configuration; private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictScopeManager _scopeManager; private readonly IPermissionDataSeeder _permissionDataSeeder; private readonly IStringLocalizer L; public OpenIddictDataSeedContributor( IConfiguration configuration, IOpenIddictApplicationManager applicationManager, IOpenIddictScopeManager scopeManager, IPermissionDataSeeder permissionDataSeeder, IStringLocalizer l) { _configuration = configuration; _applicationManager = applicationManager; _scopeManager = scopeManager; _permissionDataSeeder = permissionDataSeeder; L = l; } [UnitOfWork] public virtual async Task SeedAsync(DataSeedContext context) { await CreateScopesAsync(); await CreateApplicationsAsync(); } private async Task CreateScopesAsync() { if (await _scopeManager.FindByNameAsync("TaskScheduling") == null) { await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor { Name = "TaskScheduling", DisplayName = "TaskScheduling API", Resources = { "TaskScheduling" } }); } } private async Task CreateApplicationsAsync() { var commonScopes = new List { OpenIddictConstants.Permissions.Scopes.Address, OpenIddictConstants.Permissions.Scopes.Email, OpenIddictConstants.Permissions.Scopes.Phone, OpenIddictConstants.Permissions.Scopes.Profile, OpenIddictConstants.Permissions.Scopes.Roles, "TaskScheduling" }; var configurationSection = _configuration.GetSection("OpenIddict:Applications"); //Web Client var webClientId = configurationSection["TaskScheduling_Web:ClientId"]; if (!webClientId.IsNullOrWhiteSpace()) { var webClientRootUrl = configurationSection["TaskScheduling_Web:RootUrl"]!.EnsureEndsWith('/'); /* TaskScheduling_Web client is only needed if you created a tiered * solution. Otherwise, you can delete this client. */ await CreateApplicationAsync( name: webClientId!, type: OpenIddictConstants.ClientTypes.Confidential, consentType: OpenIddictConstants.ConsentTypes.Implicit, displayName: "Web Application", secret: configurationSection["TaskScheduling_Web:ClientSecret"] ?? "1q2w3e*", grantTypes: new List //Hybrid flow { OpenIddictConstants.GrantTypes.AuthorizationCode, OpenIddictConstants.GrantTypes.Implicit }, scopes: commonScopes, redirectUri: $"{webClientRootUrl}signin-oidc", postLogoutRedirectUri: $"{webClientRootUrl}signout-callback-oidc" ); } //Console Test / Angular Client var consoleAndAngularClientId = configurationSection["TaskScheduling_App:ClientId"]; if (!consoleAndAngularClientId.IsNullOrWhiteSpace()) { var consoleAndAngularClientRootUrl = configurationSection["TaskScheduling_App:RootUrl"]?.TrimEnd('/'); await CreateApplicationAsync( name: consoleAndAngularClientId!, type: OpenIddictConstants.ClientTypes.Public, consentType: OpenIddictConstants.ConsentTypes.Implicit, displayName: "Console Test / Angular Application", secret: null, grantTypes: new List { OpenIddictConstants.GrantTypes.AuthorizationCode, OpenIddictConstants.GrantTypes.Password, OpenIddictConstants.GrantTypes.ClientCredentials, OpenIddictConstants.GrantTypes.RefreshToken }, scopes: commonScopes, redirectUri: consoleAndAngularClientRootUrl, postLogoutRedirectUri: consoleAndAngularClientRootUrl ); } // Blazor Client var blazorClientId = configurationSection["TaskScheduling_Blazor:ClientId"]; if (!blazorClientId.IsNullOrWhiteSpace()) { var blazorRootUrl = configurationSection["TaskScheduling_Blazor:RootUrl"]?.TrimEnd('/'); await CreateApplicationAsync( name: blazorClientId!, type: OpenIddictConstants.ClientTypes.Public, consentType: OpenIddictConstants.ConsentTypes.Implicit, displayName: "Blazor Application", secret: null, grantTypes: new List { OpenIddictConstants.GrantTypes.AuthorizationCode, }, scopes: commonScopes, redirectUri: $"{blazorRootUrl}/authentication/login-callback", postLogoutRedirectUri: $"{blazorRootUrl}/authentication/logout-callback" ); } // Swagger Client var swaggerClientId = configurationSection["TaskScheduling_Swagger:ClientId"]; if (!swaggerClientId.IsNullOrWhiteSpace()) { var swaggerRootUrl = configurationSection["TaskScheduling_Swagger:RootUrl"]?.TrimEnd('/'); await CreateApplicationAsync( name: swaggerClientId!, type: OpenIddictConstants.ClientTypes.Public, consentType: OpenIddictConstants.ConsentTypes.Implicit, displayName: "Swagger Application", secret: null, grantTypes: new List { OpenIddictConstants.GrantTypes.AuthorizationCode, }, scopes: commonScopes, redirectUri: $"{swaggerRootUrl}/swagger/oauth2-redirect.html" ); } } private async Task CreateApplicationAsync( [NotNull] string name, [NotNull] string type, [NotNull] string consentType, string displayName, string? secret, List grantTypes, List scopes, string? redirectUri = null, string? postLogoutRedirectUri = null, List? permissions = null) { if (!string.IsNullOrEmpty(secret) && string.Equals(type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase)) { throw new BusinessException(L["NoClientSecretCanBeSetForPublicApplications"]); } if (string.IsNullOrEmpty(secret) && string.Equals(type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase)) { throw new BusinessException(L["TheClientSecretIsRequiredForConfidentialApplications"]); } if (!string.IsNullOrEmpty(name) && await _applicationManager.FindByClientIdAsync(name) != null) { return; //throw new BusinessException(L["TheClientIdentifierIsAlreadyTakenByAnotherApplication"]); } var client = await _applicationManager.FindByClientIdAsync(name); if (client == null) { var application = new OpenIddictApplicationDescriptor { ClientId = name, ClientType = type, ClientSecret = secret, ConsentType = consentType, DisplayName = displayName }; Check.NotNullOrEmpty(grantTypes, nameof(grantTypes)); Check.NotNullOrEmpty(scopes, nameof(scopes)); if (new [] { OpenIddictConstants.GrantTypes.AuthorizationCode, OpenIddictConstants.GrantTypes.Implicit }.All(grantTypes.Contains)) { application.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.CodeIdToken); if (string.Equals(type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase)) { application.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.CodeIdTokenToken); application.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.CodeToken); } } if (!redirectUri.IsNullOrWhiteSpace() || !postLogoutRedirectUri.IsNullOrWhiteSpace()) { application.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Logout); } var buildInGrantTypes = new [] { OpenIddictConstants.GrantTypes.Implicit, OpenIddictConstants.GrantTypes.Password, OpenIddictConstants.GrantTypes.AuthorizationCode, OpenIddictConstants.GrantTypes.ClientCredentials, OpenIddictConstants.GrantTypes.DeviceCode, OpenIddictConstants.GrantTypes.RefreshToken }; foreach (var grantType in grantTypes) { if (grantType == OpenIddictConstants.GrantTypes.AuthorizationCode) { application.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode); application.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.Code); } if (grantType == OpenIddictConstants.GrantTypes.AuthorizationCode || grantType == OpenIddictConstants.GrantTypes.Implicit) { application.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Authorization); } if (grantType == OpenIddictConstants.GrantTypes.AuthorizationCode || grantType == OpenIddictConstants.GrantTypes.ClientCredentials || grantType == OpenIddictConstants.GrantTypes.Password || grantType == OpenIddictConstants.GrantTypes.RefreshToken || grantType == OpenIddictConstants.GrantTypes.DeviceCode) { application.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Token); application.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Revocation); application.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Introspection); } if (grantType == OpenIddictConstants.GrantTypes.ClientCredentials) { application.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.ClientCredentials); } if (grantType == OpenIddictConstants.GrantTypes.Implicit) { application.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.Implicit); } if (grantType == OpenIddictConstants.GrantTypes.Password) { application.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.Password); } if (grantType == OpenIddictConstants.GrantTypes.RefreshToken) { application.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.RefreshToken); } if (grantType == OpenIddictConstants.GrantTypes.DeviceCode) { application.Permissions.Add(OpenIddictConstants.Permissions.GrantTypes.DeviceCode); application.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Device); } if (grantType == OpenIddictConstants.GrantTypes.Implicit) { application.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.IdToken); if (string.Equals(type, OpenIddictConstants.ClientTypes.Public, StringComparison.OrdinalIgnoreCase)) { application.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.IdTokenToken); application.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.Token); } } if (!buildInGrantTypes.Contains(grantType)) { application.Permissions.Add(OpenIddictConstants.Permissions.Prefixes.GrantType + grantType); } } var buildInScopes = new [] { OpenIddictConstants.Permissions.Scopes.Address, OpenIddictConstants.Permissions.Scopes.Email, OpenIddictConstants.Permissions.Scopes.Phone, OpenIddictConstants.Permissions.Scopes.Profile, OpenIddictConstants.Permissions.Scopes.Roles }; foreach (var scope in scopes) { if (buildInScopes.Contains(scope)) { application.Permissions.Add(scope); } else { application.Permissions.Add(OpenIddictConstants.Permissions.Prefixes.Scope + scope); } } if (redirectUri != null) { if (!redirectUri.IsNullOrEmpty()) { if (!Uri.TryCreate(redirectUri, UriKind.Absolute, out var uri) || !uri.IsWellFormedOriginalString()) { throw new BusinessException(L["InvalidRedirectUri", redirectUri]); } if (application.RedirectUris.All(x => x != uri)) { application.RedirectUris.Add(uri); } } } if (postLogoutRedirectUri != null) { if (!postLogoutRedirectUri.IsNullOrEmpty()) { if (!Uri.TryCreate(postLogoutRedirectUri, UriKind.Absolute, out var uri) || !uri.IsWellFormedOriginalString()) { throw new BusinessException(L["InvalidPostLogoutRedirectUri", postLogoutRedirectUri]); } if (application.PostLogoutRedirectUris.All(x => x != uri)) { application.PostLogoutRedirectUris.Add(uri); } } } if (permissions != null) { await _permissionDataSeeder.SeedAsync( ClientPermissionValueProvider.ProviderName, name, permissions, null ); } await _applicationManager.CreateAsync(application); } } }