364 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Text.Json;
 | |
| 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.OpenIddict.Applications;
 | |
| using Volo.Abp.OpenIddict.Scopes;
 | |
| using Volo.Abp.PermissionManagement;
 | |
| using Volo.Abp.Uow;
 | |
| 
 | |
| namespace KonSoft.Shared.DbMigrator.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 IAbpApplicationManager _applicationManager;
 | |
|     private readonly IConfiguration _configuration;
 | |
|     private readonly IOpenIddictApplicationRepository _openIddictApplicationRepository;
 | |
|     private readonly IOpenIddictScopeRepository _openIddictScopeRepository;
 | |
|     private readonly IPermissionDataSeeder _permissionDataSeeder;
 | |
|     private readonly IOpenIddictScopeManager _scopeManager;
 | |
|     private readonly IStringLocalizer<OpenIddictResponse> L;
 | |
| 
 | |
|     public OpenIddictDataSeedContributor(
 | |
|         IConfiguration configuration,
 | |
|         IOpenIddictApplicationRepository openIddictApplicationRepository,
 | |
|         IAbpApplicationManager applicationManager,
 | |
|         IOpenIddictScopeRepository openIddictScopeRepository,
 | |
|         IOpenIddictScopeManager scopeManager,
 | |
|         IPermissionDataSeeder permissionDataSeeder,
 | |
|         IStringLocalizer<OpenIddictResponse> l)
 | |
|     {
 | |
|         _configuration = configuration;
 | |
|         _openIddictApplicationRepository = openIddictApplicationRepository;
 | |
|         _applicationManager = applicationManager;
 | |
|         _openIddictScopeRepository = openIddictScopeRepository;
 | |
|         _scopeManager = scopeManager;
 | |
|         _permissionDataSeeder = permissionDataSeeder;
 | |
|         L = l;
 | |
|     }
 | |
| 
 | |
|     [UnitOfWork]
 | |
|     public virtual async Task SeedAsync(DataSeedContext context)
 | |
|     {
 | |
|         await CreateScopesAsync();
 | |
|         await CreateApplicationsAsync();
 | |
|     }
 | |
| 
 | |
|     private async Task CreateScopesAsync()
 | |
|     {
 | |
|         if (await _openIddictScopeRepository.FindByNameAsync("Admin") == null)
 | |
|         {
 | |
|             await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor
 | |
|             {
 | |
|                 Name = "Admin",
 | |
|                 DisplayName = "Admin API",
 | |
|                 Resources = { "Admin" }
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         if (await _openIddictScopeRepository.FindByNameAsync("Dispatch") == null)
 | |
|         {
 | |
|             await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor
 | |
|             {
 | |
|                 Name = "Dispatch",
 | |
|                 DisplayName = "Dispatch API",
 | |
|                 Resources = { "Dispatch" }
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         if (await _openIddictScopeRepository.FindByNameAsync("Payment") == null)
 | |
|         {
 | |
|             await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor
 | |
|             {
 | |
|                 Name = "Payment",
 | |
|                 DisplayName = "Payment API",
 | |
|                 Resources = { "Payment" }
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         if (await _openIddictScopeRepository.FindByNameAsync("Report") == null)
 | |
|         {
 | |
|             await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor
 | |
|             {
 | |
|                 Name = "Report",
 | |
|                 DisplayName = "Report API",
 | |
|                 Resources = { "Report" }
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         if (await _openIddictScopeRepository.FindByNameAsync("TenantManagement") == null)
 | |
|         {
 | |
|             await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor
 | |
|             {
 | |
|                 Name = "TenantManagement",
 | |
|                 DisplayName = "TenantManagement API",
 | |
|                 Resources = { "TenantManagement" }
 | |
|             });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private async Task CreateApplicationsAsync()
 | |
|     {
 | |
|         var commonScopes = new List<string>
 | |
|         {
 | |
|             OpenIddictConstants.Permissions.Scopes.Address,
 | |
|             OpenIddictConstants.Permissions.Scopes.Email,
 | |
|             OpenIddictConstants.Permissions.Scopes.Phone,
 | |
|             OpenIddictConstants.Permissions.Scopes.Profile,
 | |
|             OpenIddictConstants.Permissions.Scopes.Roles,
 | |
|             "Admin",
 | |
|             "Dispatch",
 | |
|             "Payment",
 | |
|             "Report",
 | |
|             "TenantManagement"
 | |
|         };
 | |
| 
 | |
|         var apps = new List<OpenIddictApplicationOptions>();
 | |
|         _configuration.GetSection("OpenIddict:Applications").Bind(apps);
 | |
|         foreach (var openIddictApplication in apps)
 | |
|         {
 | |
|             await CreateApplicationAsync(openIddictApplication.Name, openIddictApplication.Type,
 | |
|                 openIddictApplication.ConsentType, openIddictApplication.DisplayName, openIddictApplication.Secret,
 | |
|                 openIddictApplication.GrantTypes, commonScopes, openIddictApplication.PostLogoutRedirectUri);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private async Task CreateApplicationAsync(
 | |
|         [NotNull] string name,
 | |
|         [NotNull] string type,
 | |
|         [NotNull] string consentType,
 | |
|         string displayName,
 | |
|         string? secret,
 | |
|         List<string> grantTypes,
 | |
|         List<string> scopes,
 | |
|         string? clientUri = null,
 | |
|         string? redirectUri = null,
 | |
|         string? postLogoutRedirectUri = null,
 | |
|         List<string>? 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"]);
 | |
|         }
 | |
| 
 | |
|         var client = await _openIddictApplicationRepository.FindByClientIdAsync(name);
 | |
| 
 | |
|         var application = new AbpApplicationDescriptor
 | |
|         {
 | |
|             ClientId = name,
 | |
|             ClientType = type,
 | |
|             ClientSecret = secret,
 | |
|             ConsentType = consentType,
 | |
|             DisplayName = displayName,
 | |
|             ClientUri = clientUri
 | |
|         };
 | |
| 
 | |
|         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
 | |
|             );
 | |
|         }
 | |
| 
 | |
|         if (client == null)
 | |
|         {
 | |
|             await _applicationManager.CreateAsync(application);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         if (!HasSameRedirectUris(client, application))
 | |
|         {
 | |
|             client.RedirectUris =
 | |
|                 JsonSerializer.Serialize(application.RedirectUris.Select(q => q.ToString().TrimEnd('/')));
 | |
|             client.PostLogoutRedirectUris =
 | |
|                 JsonSerializer.Serialize(application.PostLogoutRedirectUris.Select(q => q.ToString().TrimEnd('/')));
 | |
| 
 | |
|             await _applicationManager.UpdateAsync(client.ToModel());
 | |
|         }
 | |
| 
 | |
|         if (!HasSameScopes(client, application))
 | |
|         {
 | |
|             client.Permissions = JsonSerializer.Serialize(application.Permissions.Select(q => q.ToString()));
 | |
|             await _applicationManager.UpdateAsync(client.ToModel());
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private bool HasSameRedirectUris(OpenIddictApplication existingClient, AbpApplicationDescriptor application)
 | |
|     {
 | |
|         return existingClient.RedirectUris ==
 | |
|                JsonSerializer.Serialize(application.RedirectUris.Select(q => q.ToString().TrimEnd('/')));
 | |
|     }
 | |
| 
 | |
|     private bool HasSameScopes(OpenIddictApplication existingClient, AbpApplicationDescriptor application)
 | |
|     {
 | |
|         return existingClient.Permissions ==
 | |
|                JsonSerializer.Serialize(application.Permissions.Select(q => q.ToString().TrimEnd('/')));
 | |
|     }
 | |
| } |