Skip to content

Commit

Permalink
Store redirect URIs for One Login clients (#1162)
Browse files Browse the repository at this point in the history
  • Loading branch information
gunndabad authored Feb 12, 2024
1 parent d7a2f2c commit 3b9a365
Show file tree
Hide file tree
Showing 15 changed files with 1,631 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ public class ApplicationUserMapping : IEntityTypeConfiguration<ApplicationUser>
public void Configure(EntityTypeBuilder<ApplicationUser> builder)
{
builder.Property(e => e.ApiRoles).HasColumnType("varchar[]");
builder.Property(e => e.OneLoginClientId).HasMaxLength(50);
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");
}
}

Expand Down

Large diffs are not rendered by default.

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

#nullable disable

namespace TeachingRecordSystem.Core.DataStore.Postgres.Migrations
{
/// <inheritdoc />
public partial class OneLoginAuthSchemeInfo : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "is_oidc_client",
table: "users",
type: "boolean",
nullable: true);

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

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

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

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

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

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

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

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

migrationBuilder.DropColumn(
name: "one_login_redirect_uri_path",
table: "users");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -988,16 +988,40 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("varchar[]")
.HasColumnName("api_roles");

b.Property<bool>("IsOidcClient")
.HasColumnType("boolean")
.HasColumnName("is_oidc_client");

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

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

b.Property<string>("OneLoginPostLogoutRedirectUriPath")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("one_login_post_logout_redirect_uri_path");

b.Property<string>("OneLoginPrivateKeyPem")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)")
.HasColumnName("one_login_private_key_pem");

b.Property<string>("OneLoginRedirectUriPath")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("one_login_redirect_uri_path");

b.HasIndex("OneLoginAuthenticationSchemeName")
.IsUnique()
.HasDatabaseName("ix_users_one_login_authentication_scheme_name")
.HasFilter("one_login_authentication_scheme_name is not null");

b.HasDiscriminator().HasValue(2);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,20 @@ public class User : UserBase

public class ApplicationUser : UserBase
{
public const int AuthenticationSchemeNameMaxLength = 50;
public const int RedirectUriPathMaxLength = 100;
public const int OneLoginClientIdMaxLength = 50;
public const string NameUniqueIndexName = "ix_users_application_user_name";
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? OneLoginClientId { get; set; }
public string? OneLoginPrivateKeyPem { get; set; }
public string? OneLoginAuthenticationSchemeName { get; set; }
public string? OneLoginRedirectUriPath { get; set; }
public string? OneLoginPostLogoutRedirectUriPath { get; set; }
}

public class SystemUser : UserBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@ public enum ApplicationUserUpdatedEventChanges
Name = 1 << 0,
ApiRoles = 1 << 1,
OneLoginClientId = 1 << 2,
OneLoginPrivateKeyPem = 1 << 3
OneLoginPrivateKeyPem = 1 << 3,
IsOidcClient = 1 << 4,
OneLoginAuthenticationSchemeName = 1 << 5,
OneLoginRedirectUriPath = 1 << 6,
OneLoginPostLogoutRedirectUriPath = 1 << 7,
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@ public record ApplicationUser
{
public required Guid UserId { get; init; }
public required string Name { get; init; }
public required string[] ApiRoles { get; set; }
public string? OneLoginClientId { get; set; }
public string? OneLoginPrivateKeyPem { get; set; }
public required string[] ApiRoles { get; init; }
public bool IsOidcClient { get; init; }
public string? OneLoginClientId { get; init; }
public string? OneLoginPrivateKeyPem { get; init; }
public string? OneLoginAuthenticationSchemeName { get; init; }
public string? OneLoginRedirectUriPath { get; init; }
public string? OneLoginPostLogoutRedirectUriPath { get; init; }

public static ApplicationUser FromModel(DataStore.Postgres.Models.ApplicationUser user) => new()
{
UserId = user.UserId,
Name = user.Name,
ApiRoles = user.ApiRoles,
IsOidcClient = user.IsOidcClient,
OneLoginClientId = user.OneLoginClientId,
OneLoginPrivateKeyPem = user.OneLoginPrivateKeyPem
OneLoginPrivateKeyPem = user.OneLoginPrivateKeyPem,
OneLoginAuthenticationSchemeName = user.OneLoginAuthenticationSchemeName,
OneLoginRedirectUriPath = user.OneLoginRedirectUriPath,
OneLoginPostLogoutRedirectUriPath = user.OneLoginPostLogoutRedirectUriPath
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<form action="@LinkGenerator.AddApiKey(Model.ApplicationUserId)" method="post">
<h1 class="govuk-heading-l">@ViewBag.Title</h1>

<govuk-input asp-for="Key" input-class="govuk-input--width-20 govuk-input--extra-letter-spacing" label-class="govuk-label--m" autocomplete="off" />
<govuk-input asp-for="Key" input-class="govuk-input--width-20 trs-monospace" label-class="govuk-label--m" autocomplete="off" />

<govuk-button type="submit">Save</govuk-button>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<form method="post">
<h1 class="govuk-heading-l">@ViewBag.Title</h1>

<govuk-input asp-for="Key" disabled="true" input-class="govuk-input--width-20 govuk-input--extra-letter-spacing" label-class="govuk-label--m" />
<govuk-input asp-for="Key" disabled="true" input-class="govuk-input--width-20 trs-monospace" label-class="govuk-label--m" />

<govuk-button
type="submit"
Expand All @@ -36,7 +36,7 @@

<script type="text/javascript" asp-add-nonce="true">
if ('content' in document.createElement('template')) {
const keyInput = document.querySelector("#Key");
const keyInput = document.querySelector("#@Html.IdFor(m => m.Key)");
const showKeyTemplate = document.querySelector('#showkey');
const showKey = showKeyTemplate.content.cloneNode(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@page "/application-users/{userId}"
@addTagHelper *, Joonasw.AspNetCore.SecurityHeaders
@model TeachingRecordSystem.SupportUi.Pages.ApplicationUsers.EditApplicationUserModel
@inject IClock Clock
@{
Expand Down Expand Up @@ -41,7 +42,7 @@
{
<tr class="govuk-table__row">
<td class="govuk-table__cell">
<a href="@LinkGenerator.EditApiKey(key.ApiKeyId)" class="govuk-link" data-testid="[email protected]">@key.ApiKeyId</a>
<a href="@LinkGenerator.EditApiKey(key.ApiKeyId)" class="govuk-link trs-monospace" data-testid="[email protected]">@key.ApiKeyId</a>
</td>
<td class="govuk-table__cell" data-testid="Expiry">
@if (key.Expires is DateTime expires)
Expand Down Expand Up @@ -75,11 +76,54 @@
<govuk-button-link href="@LinkGenerator.AddApiKey(Model.UserId)" class="govuk-button--secondary" data-testid="AddApiKey">Add API key</govuk-button-link>
</div>

<h2 class="govuk-heading-m">One Login</h2>
<govuk-input asp-for="OneLoginClientId" label-class="govuk-label--s" autocomplete="off" />
<govuk-textarea asp-for="OneLoginPrivateKeyPem" label-class="govuk-label--s" />
<govuk-checkboxes asp-for="IsOidcClient">
<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="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-prefix>@Model.OneLoginRedirectUriBase</govuk-input-prefix>
</govuk-input>

<govuk-input asp-for="OneLoginPostLogoutRedirectUriPath" label-class="govuk-label--s" autocomplete="off" spellcheck="false">
<govuk-input-prefix>@Model.OneLoginRedirectUriBase</govuk-input-prefix>
</govuk-input>
</govuk-checkboxes-item-conditional>
</govuk-checkboxes-item>
</govuk-checkboxes>

<govuk-button type="submit">Save changes</govuk-button>
</form>
</div>
</div>

<template id="showkey">
<govuk-checkboxes name="ShowKey" input-id="ShowKey" class="govuk-checkboxes--small">
<govuk-checkboxes-item value="true">Show key</govuk-checkboxes-item>
</govuk-checkboxes>
</template>

<script type="text/javascript" asp-add-nonce="true">
if ('content' in document.createElement('template')) {
const keyInput = document.querySelector("#@Html.IdFor(m => m.OneLoginPrivateKeyPem)");
if (keyInput.value) {
const showKeyTemplate = document.querySelector('#showkey');
const showKey = showKeyTemplate.content.cloneNode(true);
const showKeyCheckbox = showKey.querySelector('input');
const setInputTypeFromShowKeyValue = () => keyInput.style.display = showKeyCheckbox.checked ? '' : 'none';
setInputTypeFromShowKeyValue();
showKeyCheckbox.addEventListener('change', setInputTypeFromShowKeyValue);
const keyFormGroup = keyInput.parentNode;
keyInput.classList.add('govuk-!-margin-bottom-0');
keyFormGroup.querySelector('.govuk-hint').after(showKey);
}
}
</script>
Loading

0 comments on commit 3b9a365

Please sign in to comment.