Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Comment thread
jeastham1993 marked this conversation as resolved.
Outdated
Binary file not shown.
Binary file added .github/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ namespace Stickerlandia.UserManagement.AWS;

public static class ServiceExtensions
{
public static IServiceCollection AddAwsAdapters(this IServiceCollection services, IConfiguration configuration)
public static IServiceCollection AddAwsAdapters(this IServiceCollection services, IConfiguration configuration, bool enableDefaultUi = true)
{
ArgumentNullException.ThrowIfNull(configuration);

services.AddPostgresAuthServices(configuration);
services.AddPostgresAuthServices(configuration, enableDefaultUi: enableDefaultUi);

services.Configure<AwsConfiguration>(
configuration.GetSection("Aws"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,7 @@ public async Task UpdateAccount(UserAccount userAccount)
// Create outbox items for domain events
foreach (var evt in userAccount.DomainEvents)
{
var outboxItem = new PostgresOutboxItem
{
Id = Guid.NewGuid().ToString(),
EventType = evt.EventName,
EventData = evt.ToJsonString(),
EmailAddress = userAccount.EmailAddress,
EventTime = DateTime.UtcNow,
Processed = false,
Failed = false
};

await dbContext.OutboxItems.AddAsync(outboxItem);
await this.StoreEventFor(userAccount.Id.Value, evt);
}

await dbContext.SaveChangesAsync();
Expand Down Expand Up @@ -223,6 +212,25 @@ public async Task<bool> DoesEmailExistAsync(string emailAddress)
}
}

public async Task StoreEventFor(string accountId, DomainEvent domainEvent)
Comment thread
jeastham1993 marked this conversation as resolved.
Outdated
{
ArgumentException.ThrowIfNullOrEmpty(accountId, nameof(accountId));
ArgumentNullException.ThrowIfNull(domainEvent, nameof(domainEvent));

var outboxItem = new PostgresOutboxItem
{
Id = Guid.NewGuid().ToString(),
EventType = domainEvent.EventName,
EventData = domainEvent.ToJsonString(),
EmailAddress = accountId,
EventTime = DateTime.UtcNow,
Processed = false,
Failed = false
};

await dbContext.OutboxItems.AddAsync(outboxItem);
}

public async Task<List<OutboxItem>> GetUnprocessedItemsAsync(int maxCount = 100)
{
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Stickerlandia.UserManagement.Auth;
using Stickerlandia.UserManagement.Core;
using Stickerlandia.UserManagement.Core.Outbox;
Expand All @@ -15,10 +16,10 @@ namespace Stickerlandia.UserManagement.Agnostic;

public static class ServiceExtensions
{
public static IServiceCollection AddAgnosticAdapters(this IServiceCollection services, IConfiguration configuration)
public static IServiceCollection AddAgnosticAdapters(this IServiceCollection services, IConfiguration configuration, bool enableDefaultUi = true)
{
services.AddKafkaMessaging(configuration);
services.AddPostgresAuthServices(configuration);
services.AddPostgresAuthServices(configuration, enableDefaultUi);

return services;
}
Expand Down Expand Up @@ -56,7 +57,8 @@ public static IServiceCollection AddKafkaMessaging(this IServiceCollection servi
}

public static IServiceCollection AddPostgresAuthServices(this IServiceCollection services,
IConfiguration configuration)
IConfiguration configuration,
bool enableDefaultUi = true)
{
services.AddDbContext<UserManagementDbContext>(options =>
{
Expand All @@ -65,10 +67,18 @@ public static IServiceCollection AddPostgresAuthServices(this IServiceCollection
options.UseOpenIddict();
});

services.AddIdentityCore<PostgresUserAccount>()
var identityOptions = services.AddIdentity<PostgresUserAccount, IdentityRole>(options =>
{
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<UserManagementDbContext>()
.AddDefaultTokenProviders();

if (enableDefaultUi)
{
identityOptions.AddDefaultUI();
}

var disableSsl = false;

if (configuration.GetValue<bool>("DISABLE_SSL")) disableSsl = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
<PackageReference Include="OpenIddict.Validation.AspNetCore" Version="6.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.18" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.16" />
<PackageReference Include="OpenIddict.AspNetCore" Version="6.3.0" />
<PackageReference Include="OpenIddict.Server.AspNetCore" Version="6.3.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Stickerlandia.UserManagement.Core;

namespace Stickerlandia.UserManagement.Agnostic;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
@page
@model AccessDeniedModel
@{
ViewData["Title"] = "Access denied";
}

<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<img src="https://tailwindcss.com/plus-assets/img/logos/mark.svg?color=indigo&shade=600"
alt="Stickerlandia Logo"
class="mx-auto h-10 w-auto"/>
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Access denied</h2>
</div>

<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-md">
<div class="text-center space-y-6">
<div class="rounded-md bg-red-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-red-800">
Access Denied
</h3>
<div class="mt-2 text-sm text-red-700">
<p>You do not have permission to access this resource. This could be because:</p>
<ul class="list-disc list-inside mt-2 space-y-1">
<li>You are not signed in</li>
<li>Your account doesn't have the required permissions</li>
<li>The resource you're trying to access has been restricted</li>
</ul>
</div>
</div>
</div>
</div>

<div class="space-y-4">
<div>
<a asp-page="./Login"
class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
Sign in
</a>
</div>
<div>
<a href="/"
class="flex w-full justify-center rounded-md bg-white px-3 py-1.5 text-sm/6 font-semibold text-gray-900 outline-1 -outline-offset-1 outline-gray-300 hover:bg-gray-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
Go to home page
</a>
</div>
<div>
<button onclick="history.back()"
class="flex w-full justify-center rounded-md bg-white px-3 py-1.5 text-sm/6 font-semibold text-gray-900 outline-1 -outline-offset-1 outline-gray-300 hover:bg-gray-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
Go back
</button>
</div>
</div>

<div class="text-sm text-gray-500">
<p>If you believe this is an error, please contact support.</p>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable

#pragma warning disable CA1515

using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Stickerlandia.UserManagement.Api.Areas.Identity.Pages.Account
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class AccessDeniedModel : PageModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public void OnGet()
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@page
@model LoginModel

@{
ViewData["Title"] = "Log in";
}

<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
<img src="~/img/dd_logo_v_rgb.png" alt="Datadog Logo"
class="mx-auto h-10 w-auto"/>
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Sign in to your account</h2>
</div>

<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
<form id="account" method="post" class="space-y-6">
<div>
<div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
<label asp-for="Input.Email" class="block text-sm/6 font-medium text-gray-900">Email</label>
<div class="mt-2">
<input asp-for="Input.Email"
class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
autocomplete="username" aria-required="true" placeholder="name@example.com"/>
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
</div>

<div>
<div class="flex items-center justify-between">

<label asp-for="Input.Password" class="block text-sm/6 font-medium text-gray-900">Password</label>
<div class="text-sm">
<a id="forgot-password" asp-page="./ForgotPassword"
class="font-semibold text-indigo-600 hover:text-indigo-500">Forgot your password?</a>
</div>
</div>
<div class="mt-2">
<input asp-for="Input.Password"
class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
autocomplete="current-password"
aria-required="true" placeholder="password"/>
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
</div>

<div>
<button id="login-submit"
type="submit"
class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
Sign in
</button>
</div>
</form>

<p class="mt-10 text-center text-sm/6 text-gray-500">
Not a member?
<a asp-page="./Register" class="font-semibold text-indigo-600 hover:text-indigo-500"
asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
</p>
</div>
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
@{
if ((Model.ExternalLogins?.Count ?? 0) > 0)
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl"
method="post" class="space-y-6">
<div>
<p>
@foreach (var provider in Model.ExternalLogins!)
{
<button type="submit" class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" name="provider" value="@provider.Name"
title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
</div>
</div>
@* *@
@* @section Scripts { *@
@* <partial name="_ValidationScriptsPartial" /> *@
@* } *@
Loading
Loading