Skip to content

Commit

Permalink
Add OIDC attributes to ApplicationUser (#1238)
Browse files Browse the repository at this point in the history
  • Loading branch information
gunndabad authored Mar 12, 2024
1 parent 35e69b9 commit 0e866e6
Show file tree
Hide file tree
Showing 13 changed files with 2,096 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,18 @@ public class ApplicationUserMapping : IEntityTypeConfiguration<ApplicationUser>
public void Configure(EntityTypeBuilder<ApplicationUser> builder)
{
builder.Property(e => e.ApiRoles).HasColumnType("varchar[]");
builder.Property(e => e.ClientId).HasMaxLength(ApplicationUser.ClientIdMaxLength);
builder.Property(e => e.ClientSecret).HasMaxLength(ApplicationUser.ClientSecretMaxLength);
builder.Property(e => e.RedirectUris).HasColumnType("varchar[]");
builder.Property(e => e.PostLogoutRedirectUris).HasColumnType("varchar[]");
builder.Property(e => e.OneLoginClientId).HasMaxLength(ApplicationUser.OneLoginClientIdMaxLength);
builder.Property(e => e.OneLoginPrivateKeyPem).HasMaxLength(2000);
builder.Property(e => e.OneLoginAuthenticationSchemeName).HasMaxLength(ApplicationUser.AuthenticationSchemeNameMaxLength);
builder.Property(e => e.OneLoginRedirectUriPath).HasMaxLength(ApplicationUser.RedirectUriPathMaxLength);
builder.Property(e => e.OneLoginPostLogoutRedirectUriPath).HasMaxLength(ApplicationUser.RedirectUriPathMaxLength);
builder.HasIndex(e => e.OneLoginAuthenticationSchemeName).IsUnique().HasDatabaseName(ApplicationUser.OneLoginAuthenticationSchemeNameUniqueIndexName)
.HasFilter("one_login_authentication_scheme_name is not null");
builder.HasIndex(e => e.ClientId).IsUnique().HasDatabaseName(ApplicationUser.ClientIdUniqueIndexName).HasFilter("client_id is not null");
}
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace TeachingRecordSystem.Core.DataStore.Postgres.Migrations
{
/// <inheritdoc />
public partial class ApplicationUserOidcInfo : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "client_id",
table: "users",
type: "character varying(50)",
maxLength: 50,
nullable: true);

migrationBuilder.AddColumn<string>(
name: "client_secret",
table: "users",
type: "character varying(200)",
maxLength: 200,
nullable: true);

migrationBuilder.AddColumn<List<string>>(
name: "post_logout_redirect_uris",
table: "users",
type: "varchar[]",
nullable: true);

migrationBuilder.AddColumn<List<string>>(
name: "redirect_uris",
table: "users",
type: "varchar[]",
nullable: true);

migrationBuilder.CreateIndex(
name: "ix_users_client_id",
table: "users",
column: "client_id",
unique: true,
filter: "client_id is not null");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "ix_users_client_id",
table: "users");

migrationBuilder.DropColumn(
name: "client_id",
table: "users");

migrationBuilder.DropColumn(
name: "client_secret",
table: "users");

migrationBuilder.DropColumn(
name: "post_logout_redirect_uris",
table: "users");

migrationBuilder.DropColumn(
name: "redirect_uris",
table: "users");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
Expand Down Expand Up @@ -1417,6 +1418,16 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("varchar[]")
.HasColumnName("api_roles");

b.Property<string>("ClientId")
.HasMaxLength(50)
.HasColumnType("character varying(50)")
.HasColumnName("client_id");

b.Property<string>("ClientSecret")
.HasMaxLength(200)
.HasColumnType("character varying(200)")
.HasColumnName("client_secret");

b.Property<bool>("IsOidcClient")
.HasColumnType("boolean")
.HasColumnName("is_oidc_client");
Expand Down Expand Up @@ -1446,6 +1457,19 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("character varying(100)")
.HasColumnName("one_login_redirect_uri_path");

b.Property<List<string>>("PostLogoutRedirectUris")
.HasColumnType("varchar[]")
.HasColumnName("post_logout_redirect_uris");

b.Property<List<string>>("RedirectUris")
.HasColumnType("varchar[]")
.HasColumnName("redirect_uris");

b.HasIndex("ClientId")
.IsUnique()
.HasDatabaseName("ix_users_client_id")
.HasFilter("client_id is not null");

b.HasIndex("OneLoginAuthenticationSchemeName")
.IsUnique()
.HasDatabaseName("ix_users_one_login_authentication_scheme_name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@ public class ApplicationUser : UserBase
{
public const int AuthenticationSchemeNameMaxLength = 50;
public const int RedirectUriPathMaxLength = 100;
public const int ClientIdMaxLength = 50;
public const int ClientSecretMaxLength = 200;
public const int ClientSecretMinLength = 16;
public const int OneLoginClientIdMaxLength = 50;
public const string NameUniqueIndexName = "ix_users_application_user_name";
public const string ClientIdUniqueIndexName = "ix_users_client_id";
public const string OneLoginAuthenticationSchemeNameUniqueIndexName = "ix_users_one_login_authentication_scheme_name";

public required string[] ApiRoles { get; set; }
public ICollection<ApiKey> ApiKeys { get; } = null!;
public bool IsOidcClient { get; set; }
public string? ClientId { get; set; }
public string? ClientSecret { get; set; }
public List<string>? RedirectUris { get; set; }
public List<string>? PostLogoutRedirectUris { get; set; }
public string? OneLoginClientId { get; set; }
public string? OneLoginPrivateKeyPem { get; set; }
public string? OneLoginAuthenticationSchemeName { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,12 @@ public static string ToCommaSeparatedString(
_ => string.Join(", ", valuesArray[0..^2].Append(string.Join($" {finalValuesConjunction} ", valuesArray[^2..])))
};
}

public static bool SequenceEqualIgnoringOrder<T>(this IEnumerable<T> first, IEnumerable<T> second)
where T : IComparable
{
var firstArray = first.ToArray().OrderBy(s => s);
var secondArray = second.ToArray().OrderBy(s => s);
return firstArray.SequenceEqual(secondArray);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@ public enum ApplicationUserUpdatedEventChanges
OneLoginAuthenticationSchemeName = 1 << 5,
OneLoginRedirectUriPath = 1 << 6,
OneLoginPostLogoutRedirectUriPath = 1 << 7,
ClientId = 1 << 8,
ClientSecret = 1 << 9,
RedirectUris = 1 << 10,
PostLogoutRedirectUris = 1 << 11,
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ public record ApplicationUser
public required string Name { get; init; }
public required string[] ApiRoles { get; init; }
public bool IsOidcClient { get; init; }
public string? ClientId { get; init; }
public string? ClientSecret { get; init; }
public IReadOnlyCollection<string>? RedirectUris { get; init; }
public IReadOnlyCollection<string>? PostLogoutRedirectUris { get; init; }
public string? OneLoginClientId { get; init; }
public string? OneLoginPrivateKeyPem { get; init; }
public string? OneLoginAuthenticationSchemeName { get; init; }
Expand All @@ -18,6 +22,10 @@ public record ApplicationUser
Name = user.Name,
ApiRoles = user.ApiRoles,
IsOidcClient = user.IsOidcClient,
ClientId = user.ClientId,
ClientSecret = user.ClientSecret,
RedirectUris = user.RedirectUris,
PostLogoutRedirectUris = user.PostLogoutRedirectUris,
OneLoginClientId = user.OneLoginClientId,
OneLoginPrivateKeyPem = user.OneLoginPrivateKeyPem,
OneLoginAuthenticationSchemeName = user.OneLoginAuthenticationSchemeName,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace TeachingRecordSystem.SupportUi.Infrastructure.ModelBinding;

public class MultiLineStringModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var modelType = bindingContext.ModelType;
if (!typeof(string[]).IsAssignableTo(modelType))
{
throw new InvalidOperationException($"Cannot bind to {modelType}.");
}

var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
var value = valueProviderResult.FirstValue ?? string.Empty;
var splitByLines = value.Split("\n", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);

bindingContext.Result = ModelBindingResult.Success(splitByLines);

return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,27 @@
<govuk-checkboxes-item value="@true" label-class="govuk-label--m">
@Html.DisplayNameFor(m => m.IsOidcClient)
<govuk-checkboxes-item-conditional>
<govuk-input asp-for="OneLoginAuthenticationSchemeName" label-class="govuk-label--s" input-class="govuk-!-width-one-half trs-monospace" autocomplete="off" spellcheck="false" />
<govuk-input asp-for="ClientId" label-class="govuk-label--s" input-class="govuk-!-width-two-thirds trs-monospace" autocomplete="off" spellcheck="false" />

<govuk-input asp-for="ClientSecret" label-class="govuk-label--s" input-class="trs-monospace" autocomplete="off" spellcheck="false" />

<govuk-textarea asp-for="RedirectUris" label-class="govuk-label--s" textarea-class="trs-monospace trs-nowrap">
<govuk-textarea-value>@string.Join("\n", Model.RedirectUris!)</govuk-textarea-value>
</govuk-textarea>

<govuk-textarea asp-for="PostLogoutRedirectUris" label-class="govuk-label--s" textarea-class="trs-monospace trs-nowrap">
<govuk-textarea-value>@string.Join("\n", Model.PostLogoutRedirectUris!)</govuk-textarea-value>
</govuk-textarea>

<govuk-input asp-for="OneLoginAuthenticationSchemeName" label-class="govuk-label--s" input-class="govuk-!-width-two-thirds trs-monospace" autocomplete="off" spellcheck="false" />

<govuk-input asp-for="OneLoginClientId" label-class="govuk-label--s" input-class="trs-monospace" autocomplete="off" spellcheck="false" />

<govuk-textarea asp-for="OneLoginPrivateKeyPem" label-class="govuk-label--s" textarea-class="trs-monospace trs-nowrap" autocomplete="off" spellcheck="false" />

<govuk-input asp-for="OneLoginRedirectUriPath" label-class="govuk-label--s" autocomplete="off" spellcheck="false" />
<govuk-input asp-for="OneLoginRedirectUriPath" label-class="govuk-label--s" input-class="trs-monospace" autocomplete="off" spellcheck="false" />

<govuk-input asp-for="OneLoginPostLogoutRedirectUriPath" label-class="govuk-label--s" autocomplete="off" spellcheck="false"/>
<govuk-input asp-for="OneLoginPostLogoutRedirectUriPath" label-class="govuk-label--s" input-class="trs-monospace" autocomplete="off" spellcheck="false" />
</govuk-checkboxes-item-conditional>
</govuk-checkboxes-item>
</govuk-checkboxes>
Expand Down
Loading

0 comments on commit 0e866e6

Please sign in to comment.