Skip to content

Commit

Permalink
fix: added support for generating signin tokens or development
Browse files Browse the repository at this point in the history
  • Loading branch information
pksorensen committed Aug 17, 2024
1 parent 493a68f commit 758e2cc
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
using Azure.Core;
using Azure.Identity;
using Azure.Security.KeyVault.Certificates;
using EAVFramework.Configuration;
using EAVFW.Extensions.SecurityModel;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -523,10 +526,37 @@ public static IResourceBuilder<EAVFWModelProjectResource> FromBackup(this IResou
/// <param name="target">An <see cref="IResourceBuilder{T}"/> representing the target <see cref="SqlServerDatabaseResource"/> to publish the model to.</param>
/// <returns>An <see cref="IResourceBuilder{T}"/> that can be used to further customize the resource.</returns>
public static IResourceBuilder<EAVFWModelProjectResource> PublishTo(
this IResourceBuilder<EAVFWModelProjectResource> builder, IResourceBuilder<SqlServerDatabaseResource> target)
this IResourceBuilder<EAVFWModelProjectResource> builder,
IResourceBuilder<SqlServerDatabaseResource> target,
string administratorEmail, Guid initialAdministratorUserId, string Username, string schema = "dbo"
)
{
builder.ApplicationBuilder.Services.TryAddLifecycleHook<PublishEAVFWProjectLifecycleHook>();
builder.WithAnnotation(new TargetDatabaseResourceAnnotation(target.Resource.Name, target.Resource), ResourceAnnotationMutationBehavior.Replace);
builder.WithAnnotation(new TargetDatabaseResourceAnnotation(target.Resource.Name, target.Resource)
{
InitialEmail = administratorEmail, InitialIdentity = initialAdministratorUserId, Schema = schema, InitialUsername = Username, UserPrincipalName = Username.Replace(" ","")
}, ResourceAnnotationMutationBehavior.Replace);
return builder;
}
public static IResourceBuilder<T> WithSigninUrl<T>(this IResourceBuilder<T> builder, IResourceBuilder<EAVFWModelProjectResource> model, IResourceBuilder<ProjectResource> project=null)
where T:Resource
{
model.WithAnnotation(new CreateSigninUrlAnnotation(builder.Resource,project?.Resource??builder.Resource as IResource));
return builder;
}
public static IResourceBuilder<EAVFWModelProjectResource> WithSinginToken<TContext, TIdentity, TSignin>(

this IResourceBuilder<EAVFWModelProjectResource> builder, Action<IServiceCollection> services = null, Action<SqlServerDbContextOptionsBuilder> sql=null)
where TContext : DynamicContext
where TIdentity : DynamicEntity, IIdentity
where TSignin : DynamicEntity, ISigninRecord, new()
{
builder.ApplicationBuilder.Services.TryAddLifecycleHook<PublishEAVFWProjectLifecycleHook>();
builder.WithAnnotation< CreateSigninTokenAnnotation>(new CreateSigninTokenAnnotation<TContext, TIdentity, TSignin>(builder.Resource)
{
ServiceCollectionExtender = services,
SqlExtender = sql,
}, ResourceAnnotationMutationBehavior.Replace);
return builder;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace EAVFramework.Extensions.Aspire.Hosting
{
public sealed class EAVFWModelProjectResource(string name) : Resource(name)
{


public string GetModelPath()
{
var projectMetadata = Annotations.OfType<IProjectMetadata>().FirstOrDefault();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -24,6 +24,8 @@
<PackageReference Include="Azure.Security.KeyVault.Certificates" Version="4.6.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite" Version="8.0.7" />
<PackageReference Include="Aspire.Hosting.Azure.KeyVault" Version="8.1.0" />
<PackageReference Include="EAVFW.Extensions.SecurityModel" Version="2.2.0" />
<PackageReference Include="EAVFW.Extensions.DynamicManifest" Version="3.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class NeedsAnnotation(IResource resource) : IResourceAnnotation
/// <summary>
/// The states to wait for. If null, it will wait for the resource to be in the "Running" state.
/// </summary>
public string[]? States { get; set; }
public string[] States { get; set; }

/// <summary>
/// Indicates if it should wait until the resource has run to completion.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Azure.Provisioning;
using EAVFramework.Configuration;
using EAVFW.Extensions.Manifest.SDK;
using EAVFW.Extensions.Manifest.SDK.Migrations;
using EAVFW.Extensions.SecurityModel;
using Grpc.Core;
using IdentityModel;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand All @@ -16,6 +24,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Resource = Aspire.Hosting.ApplicationModel.Resource;

namespace EAVFramework.Extensions.Aspire.Hosting
{
Expand Down Expand Up @@ -354,14 +363,17 @@ await _resourceNotificationService.PublishUpdateAsync(eavBuildResource,


public class PublishEAVFWProjectLifecycleHook : IDistributedApplicationLifecycleHook

{
private readonly ResourceLoggerService _resourceLoggerService;
private readonly ILogger<PublishEAVFWProjectLifecycleHook> _aspirelogger;
private readonly ResourceNotificationService _resourceNotificationService;

public PublishEAVFWProjectLifecycleHook(ResourceLoggerService resourceLoggerService,
public PublishEAVFWProjectLifecycleHook(ResourceLoggerService resourceLoggerService, ILogger<PublishEAVFWProjectLifecycleHook> aspirelogger,
ResourceNotificationService resourceNotificationService)
{
_resourceLoggerService = resourceLoggerService ?? throw new ArgumentNullException(nameof(resourceLoggerService));
_aspirelogger = aspirelogger;
_resourceNotificationService = resourceNotificationService ?? throw new ArgumentNullException(nameof(resourceNotificationService));
}

Expand All @@ -385,7 +397,11 @@ public async Task BeforeStartAsync(DistributedApplicationModel application, Canc
var modelProjectPath = modelResource.GetModelPath();
var targetDatabaseResourceName = modelResource.Annotations.OfType<TargetDatabaseResourceAnnotation>().Single().TargetDatabaseResourceName;
if (!modelResource.TryGetLastAnnotation<TargetDatabaseResourceAnnotation>(out var targetDatabaseResourceAnnotation)){
return;
}
var targetDatabaseResourceName = targetDatabaseResourceAnnotation.TargetDatabaseResourceName;
var targetDatabaseResource = application.Resources.OfType<SqlServerDatabaseResource>().Single(r => r.Name == targetDatabaseResourceName);
var targetSQLServerResource = targetDatabaseResource.Parent;
Expand Down Expand Up @@ -471,12 +487,12 @@ await _resourceNotificationService.PublishUpdateAsync(modelResource,
var migrationCount = await GetMigrationsCountAsync(targetDatabaseResource, connectionString);
if (migrationCount == 0)
{
await DoMigrationAsync(modelProjectPath, targetDatabaseResource, connectionString);
await DoMigrationAsync(modelProjectPath , targetDatabaseResourceAnnotation, targetDatabaseResource, connectionString);
}
migrationannotation.Success = true;
await _resourceNotificationService.PublishUpdateAsync(modelResource,
state => state with { State = new ResourceStateSnapshot(KnownResourceStates.Finished, KnownResourceStateStyles.Success) });
migrationannotation.Success = true;
state => state with { State = new ResourceStateSnapshot($"migrations was created", KnownResourceStateStyles.Info) });
}
catch (SqlException sqlexception)
Expand All @@ -495,6 +511,51 @@ await _resourceNotificationService.PublishUpdateAsync(modelResource,
}
}
if (modelResource.TryGetLastAnnotation<CreateSigninTokenAnnotation>(out var tokenannotation)){
try
{
await _resourceNotificationService.PublishUpdateAsync(modelResource,
state => state with { State = new ResourceStateSnapshot("Creating signin link", KnownResourceStateStyles.Info) });
foreach(var target in modelResource.Annotations.OfType<CreateSigninUrlAnnotation>())
{
var link = await tokenannotation.GenerateLink(target,cancellationToken);
await _resourceNotificationService.PublishUpdateAsync(target.Target,
state => state with
{
Properties = [.. state.Properties, new ResourcePropertySnapshot("signinlink", link.Link) ],
Urls = [.. state.Urls, new UrlSnapshot("signinlink", link.Link,true), new UrlSnapshot("signinlink", link.Link, false)],
});
if (target.Project.TryGetEndpoints(out var endpoints))
{
var targetlogger = _resourceLoggerService.GetLogger(target.Target);
targetlogger.LogInformation("Sign in with: {singinlink}", endpoints?.FirstOrDefault()?.AllocatedEndpoint.UriString+ link.Link);
_aspirelogger.LogInformation("Sign in to {project}: {singinlink}", target.Target.Name, endpoints?.FirstOrDefault()?.AllocatedEndpoint.UriString + link.Link);
}
}
await _resourceNotificationService.PublishUpdateAsync(modelResource,
state => state with { State = new ResourceStateSnapshot("signin link crated", KnownResourceStateStyles.Info) });
}
catch (Exception ex)
{
}
}
await _resourceNotificationService.PublishUpdateAsync(modelResource,
state => state with { State = new ResourceStateSnapshot(KnownResourceStates.Finished, KnownResourceStateStyles.Success) });
return;
}
catch (Exception ex)
{
Expand All @@ -519,8 +580,8 @@ await _resourceNotificationService.PublishUpdateAsync(modelResource,
}, cancellationToken);

}

private static async Task DoMigrationAsync(string modelProjectPath, SqlServerDatabaseResource targetDatabaseResource, string connectionString)
private static async Task DoMigrationAsync(string modelProjectPath, TargetDatabaseResourceAnnotation targetDatabaseResourceAnnotation, SqlServerDatabaseResource targetDatabaseResource, string connectionString)
{
var variablegenerator = new SQLClientParameterGenerator();
var migrator = new SQLMigrationGenerator(variablegenerator, new ManifestPermissionGenerator(variablegenerator));
Expand All @@ -534,12 +595,12 @@ private static async Task DoMigrationAsync(string modelProjectPath, SqlServerDat
var replacements = new Dictionary<string, string>
{
["DBName"] = targetDatabaseResource.DatabaseName,
["DBSchema"] = "dbo",
["SystemAdminSecurityGroupId"] = "1b714972-8d0a-4feb-b166-08d93c6ae328",
["UserGuid"] = "A0461D73-E979-449C-B24F-A3B3D6711D61",
["UserName"] = "Poul Kjeldager",
["UserEmail"] = "[email protected]",
["UserPrincipalName"] = "PoulKjeldagerSorensen"
["DBSchema"] = targetDatabaseResourceAnnotation.Schema,
["SystemAdminSecurityGroupId"] = targetDatabaseResourceAnnotation.InitialSystemSecurityGroupId,
["UserGuid"] = targetDatabaseResourceAnnotation.InitialIdentity.ToString(),
["UserName"] = targetDatabaseResourceAnnotation.InitialUsername ?? "Poul Kjeldager",
["UserEmail"] = targetDatabaseResourceAnnotation.InitialEmail,
["UserPrincipalName"] = targetDatabaseResourceAnnotation.UserPrincipalName ?? "PoulKjeldagerSorensen"

};

Expand Down
Loading

0 comments on commit 758e2cc

Please sign in to comment.