Id Stores from db
Some checks failed
Dotnet build and test / log-the-inputs (push) Failing after 2s
Dotnet build and test / build (push) Failing after 2s

This commit is contained in:
Paul Schneider
2025-08-24 16:07:53 +01:00
parent 34e028e6d1
commit 0ca4259451
23 changed files with 2934 additions and 233 deletions

View File

@ -8,9 +8,13 @@
<PackageVersion Include="bootstrap" Version="5.3.7" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="Google.Apis.Calendar.v3" Version="1.69.0.3746" />
<PackageVersion Include="Google.Apis.Compute.v1" Version="1.70.0.3841" />
<PackageVersion Include="Google.Apis.Compute.v1" Version="1.70.0.3871" />
<PackageVersion Include="HigginsSoft.IdentityServer8" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.AspNetIdentity" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.Storage" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.EntityFramework.Storage" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.EntityFramework" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.Security" Version="8.0.5-preview-net9" />
<PackageVersion Include="IdentityModel.AspNetCore" Version="4.3.0" />
<PackageVersion Include="MailKit" Version="4.13.0" />
<PackageVersion Include="Microsoft.AspNetCore.Antiforgery" Version="2.3.0" />

View File

@ -43,13 +43,13 @@ public static class Config
new IdentityResources.Email()
];
public static IEnumerable<ApiScope> TestingApiScopes =>
public static IEnumerable<ApiScope> ApiScopes =>
[
new ApiScope("scope1",new string[] {"scope1"}),
new ApiScope("scope2",new string[] {"scope2"}),
];
public static IEnumerable<Client> TestingClients =>
public static IEnumerable<Client> Clients =>
[
// m2m client credentials flow client
new Client

View File

@ -91,8 +91,6 @@ namespace Yavsc.Models
optionsBuilder.UseNpgsql(envCxStr);
base.OnConfiguring(optionsBuilder);
}
public DbSet<Client> Applications { get; set; }
/// <summary>
/// Activities referenced on this site
@ -278,6 +276,5 @@ namespace Yavsc.Models
public DbSet<Scope> Scopes { get; set; }
public DbSet<BlogSpotPublication> blogSpotPublications { get; set; }
public DbSet<Client> Client { get; set; }
}
}

View File

@ -1,29 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Yavsc.Models.Auth
{
public class Client
{
[Key][Required][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
[Required]
[MaxLength(128)]
public string DisplayName { get; set; }
[MaxLength(512)]
public string? RedirectUri { get; set; }
[MaxLength(512)]
public string? LogoutRedirectUri { get; set; }
[MaxLength(512)]
public string Secret { get; set; }
public ApplicationTypes Type { get; set; }
public bool Active { get; set; }
public int RefreshTokenLifeTime { get; set; }
public int AccessTokenLifetime { get; set; }
}
}

View File

@ -1,3 +1,6 @@
using IdentityServer8.EntityFramework.DbContexts;
using IdentityServer8.EntityFramework.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
@ -8,11 +11,12 @@ using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
[Authorize("AdministratorOnly")]
public class ClientController : Controller
{
private readonly ApplicationDbContext _context;
private readonly ConfigurationDbContext _context;
public ClientController(ApplicationDbContext context)
public ClientController(ConfigurationDbContext context)
{
_context = context;
}
@ -20,7 +24,8 @@ namespace Yavsc.Controllers
// GET: Client
public async Task<IActionResult> Index()
{
return View(await _context.Applications.ToListAsync());
return View(await _context.Clients.Include(c=>c.AllowedGrantTypes)
.Include(c=>c.RedirectUris).ToListAsync());
}
// GET: Client/Details/5
@ -31,7 +36,11 @@ namespace Yavsc.Controllers
return NotFound();
}
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
Client client = await _context.Clients.Include(
c => c.ClientSecrets
).Include(c=>c.AllowedGrantTypes)
.Include(c=>c.RedirectUris)
.SingleAsync(m => m.ClientId == id);
if (client == null)
{
return NotFound();
@ -53,9 +62,10 @@ namespace Yavsc.Controllers
{
if (ModelState.IsValid)
{
client.Id = Guid.NewGuid().ToString();
_context.Applications.Add(client);
await _context.SaveChangesAsync(User.GetUserId());
if (string.IsNullOrWhiteSpace(client.ClientId))
client.ClientId = Guid.NewGuid().ToString();
_context.Clients.Add(client);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
SetAppTypesInputValues();
@ -63,7 +73,7 @@ namespace Yavsc.Controllers
}
private void SetAppTypesInputValues()
{
IEnumerable<SelectListItem> types = new SelectListItem[] {
IEnumerable<SelectListItem> types = new SelectListItem[] {
new SelectListItem {
Text = ApplicationTypes.JavaScript.ToString(),
Value = ((int) ApplicationTypes.JavaScript).ToString() },
@ -72,7 +82,7 @@ namespace Yavsc.Controllers
Value = ((int) ApplicationTypes.NativeConfidential).ToString()
}
};
ViewData["Type"] = types;
ViewData["AccessTokenType"] = types;
}
// GET: Client/Edit/5
public async Task<IActionResult> Edit(string id)
@ -82,7 +92,7 @@ namespace Yavsc.Controllers
return NotFound();
}
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
Client client = await _context.Clients.SingleAsync(m => m.ClientId == id);
if (client == null)
{
return NotFound();
@ -99,7 +109,7 @@ namespace Yavsc.Controllers
if (ModelState.IsValid)
{
_context.Update(client);
await _context.SaveChangesAsync(User.GetUserId());
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(client);
@ -114,7 +124,7 @@ namespace Yavsc.Controllers
return NotFound();
}
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
Client client = await _context.Clients.SingleAsync(m => m.ClientId == id);
if (client == null)
{
return NotFound();
@ -128,9 +138,9 @@ namespace Yavsc.Controllers
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(string id)
{
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
_context.Applications.Remove(client);
await _context.SaveChangesAsync(User.GetUserId());
Client client = await _context.Clients.SingleAsync(m => m.ClientId == id);
_context.Clients.Remove(client);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
}

View File

@ -1,11 +1,9 @@
using System.IO.Compression;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Yavsc.Models;
using Yavsc.Models.Blog;
namespace Yavsc.Controllers
{

View File

@ -2,6 +2,11 @@ using System.Diagnostics;
using System.Globalization;
using Google.Apis.Util.Store;
using IdentityServer8;
using Microsoft.Extensions.DependencyInjection;
using IdentityServer8.Stores;
using IdentityServer8.EntityFramework;
using IdentityServer8.Extensions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
@ -29,6 +34,9 @@ using IdentityModel;
using Yavsc.Interfaces;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Npgsql;
using System.Reflection;
using IdentityServer8.EntityFramework.DbContexts;
using IdentityServer8.EntityFramework.Mappers;
namespace Yavsc.Extensions;
@ -121,7 +129,12 @@ public static class HostingExtensions
{
IServiceCollection services = builder.Services;
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
{
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"),
options => options.MigrationsAssembly("Yavsc")
);
}
);
return services.AddIdentity<ApplicationUser, IdentityRole>(
options =>
@ -226,6 +239,9 @@ public static class HostingExtensions
}
private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder)
{
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
@ -237,10 +253,19 @@ public static class HostingExtensions
options.EmitStaticAudienceClaim = true;
})
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryClients(Config.TestingClients)
.AddClientStore<ClientStore>()
.AddInMemoryApiScopes(Config.TestingApiScopes)
//.AddInMemoryIdentityResources(Config.IdentityResources)
//.AddInMemoryClients(Config.TestingClients)
//.AddInMemoryApiScopes(Config.TestingApiScopes)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddAspNetIdentity<ApplicationUser>();
builder.Services.Configure<IdentityOptions>(options =>
@ -370,9 +395,53 @@ public static class HostingExtensions
payPalSettings, googleAuthSettings, localization, loggerFactory,
app.Environment.EnvironmentName);
app.ConfigureFileServerApp();
app.InitializeDatabase();
return app;
}
private static void InitializeDatabase(this IApplicationBuilder app)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
try
{
context.Database.Migrate();
}
catch (Exception ex)
{
// TODO log
}
if (!context.Clients.Any())
{
foreach (var client in Config.Clients)
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.IdentityResources)
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiScopes.Any())
{
foreach (var resource in Config.ApiScopes)
{
context.ApiScopes.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
}
static void LoadGoogleConfig(IConfigurationRoot configuration)
{

View File

@ -9,10 +9,10 @@ using Yavsc.Models;
#nullable disable
namespace Yavsc.Server.Migrations
namespace Yavsc.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20250814102318_init")]
[Migration("20250824130510_init")]
partial class init
{
/// <inheritdoc />
@ -702,7 +702,6 @@ namespace Yavsc.Server.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("AuthorId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Content")
@ -2663,9 +2662,7 @@ namespace Yavsc.Server.Migrations
{
b.HasOne("Yavsc.Models.ApplicationUser", "Author")
.WithMany("Posts")
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("AuthorId");
b.Navigation("Author");
});

View File

@ -4,7 +4,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Yavsc.Server.Migrations
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class init : Migration
@ -800,7 +800,7 @@ namespace Yavsc.Server.Migrations
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AuthorId = table.Column<string>(type: "text", nullable: false),
AuthorId = table.Column<string>(type: "text", nullable: true),
DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UserCreated = table.Column<string>(type: "text", nullable: true),
DateModified = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
@ -816,8 +816,7 @@ namespace Yavsc.Server.Migrations
name: "FK_BlogSpot_AspNetUsers_AuthorId",
column: x => x.AuthorId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
principalColumn: "Id");
});
migrationBuilder.CreateTable(

View File

@ -8,7 +8,7 @@ using Yavsc.Models;
#nullable disable
namespace Yavsc.Server.Migrations
namespace Yavsc.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
@ -699,7 +699,6 @@ namespace Yavsc.Server.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("AuthorId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Content")
@ -2660,9 +2659,7 @@ namespace Yavsc.Server.Migrations
{
b.HasOne("Yavsc.Models.ApplicationUser", "Author")
.WithMany("Posts")
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("AuthorId");
b.Navigation("Author");
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,663 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Yavsc.Migrations.ConfigurationDb
{
/// <inheritdoc />
public partial class init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApiResources",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
AllowedAccessTokenSigningAlgorithms = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
ShowInDiscoveryDocument = table.Column<bool>(type: "boolean", nullable: false),
Created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Updated = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastAccessed = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
NonEditable = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResources", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ApiScopes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
Required = table.Column<bool>(type: "boolean", nullable: false),
Emphasize = table.Column<bool>(type: "boolean", nullable: false),
ShowInDiscoveryDocument = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopes", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Clients",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
ClientId = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ProtocolType = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
RequireClientSecret = table.Column<bool>(type: "boolean", nullable: false),
ClientName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
ClientUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
LogoUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
RequireConsent = table.Column<bool>(type: "boolean", nullable: false),
AllowRememberConsent = table.Column<bool>(type: "boolean", nullable: false),
AlwaysIncludeUserClaimsInIdToken = table.Column<bool>(type: "boolean", nullable: false),
RequirePkce = table.Column<bool>(type: "boolean", nullable: false),
AllowPlainTextPkce = table.Column<bool>(type: "boolean", nullable: false),
RequireRequestObject = table.Column<bool>(type: "boolean", nullable: false),
AllowAccessTokensViaBrowser = table.Column<bool>(type: "boolean", nullable: false),
FrontChannelLogoutUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
FrontChannelLogoutSessionRequired = table.Column<bool>(type: "boolean", nullable: false),
BackChannelLogoutUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
BackChannelLogoutSessionRequired = table.Column<bool>(type: "boolean", nullable: false),
AllowOfflineAccess = table.Column<bool>(type: "boolean", nullable: false),
IdentityTokenLifetime = table.Column<int>(type: "integer", nullable: false),
AllowedIdentityTokenSigningAlgorithms = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
AccessTokenLifetime = table.Column<int>(type: "integer", nullable: false),
AuthorizationCodeLifetime = table.Column<int>(type: "integer", nullable: false),
ConsentLifetime = table.Column<int>(type: "integer", nullable: true),
AbsoluteRefreshTokenLifetime = table.Column<int>(type: "integer", nullable: false),
SlidingRefreshTokenLifetime = table.Column<int>(type: "integer", nullable: false),
RefreshTokenUsage = table.Column<int>(type: "integer", nullable: false),
UpdateAccessTokenClaimsOnRefresh = table.Column<bool>(type: "boolean", nullable: false),
RefreshTokenExpiration = table.Column<int>(type: "integer", nullable: false),
AccessTokenType = table.Column<int>(type: "integer", nullable: false),
EnableLocalLogin = table.Column<bool>(type: "boolean", nullable: false),
IncludeJwtId = table.Column<bool>(type: "boolean", nullable: false),
AlwaysSendClientClaims = table.Column<bool>(type: "boolean", nullable: false),
ClientClaimsPrefix = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
PairWiseSubjectSalt = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Updated = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastAccessed = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
UserSsoLifetime = table.Column<int>(type: "integer", nullable: true),
UserCodeType = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
DeviceCodeLifetime = table.Column<int>(type: "integer", nullable: false),
NonEditable = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Clients", x => x.Id);
});
migrationBuilder.CreateTable(
name: "IdentityResources",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
DisplayName = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
Required = table.Column<bool>(type: "boolean", nullable: false),
Emphasize = table.Column<bool>(type: "boolean", nullable: false),
ShowInDiscoveryDocument = table.Column<bool>(type: "boolean", nullable: false),
Created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Updated = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
NonEditable = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityResources", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ApiResourceClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ApiResourceId = table.Column<int>(type: "integer", nullable: false),
Type = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceClaims", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceClaims_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiResourceProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ApiResourceId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceProperties", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceProperties_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiResourceScopes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Scope = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ApiResourceId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceScopes", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceScopes_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiResourceSecrets",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ApiResourceId = table.Column<int>(type: "integer", nullable: false),
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
Value = table.Column<string>(type: "character varying(4000)", maxLength: 4000, nullable: false),
Expiration = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
Type = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiResourceSecrets", x => x.Id);
table.ForeignKey(
name: "FK_ApiResourceSecrets_ApiResources_ApiResourceId",
column: x => x.ApiResourceId,
principalTable: "ApiResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiScopeClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ScopeId = table.Column<int>(type: "integer", nullable: false),
Type = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopeClaims", x => x.Id);
table.ForeignKey(
name: "FK_ApiScopeClaims_ApiScopes_ScopeId",
column: x => x.ScopeId,
principalTable: "ApiScopes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ApiScopeProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ScopeId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiScopeProperties", x => x.Id);
table.ForeignKey(
name: "FK_ApiScopeProperties_ApiScopes_ScopeId",
column: x => x.ScopeId,
principalTable: "ApiScopes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Type = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientClaims", x => x.Id);
table.ForeignKey(
name: "FK_ClientClaims_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientCorsOrigins",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Origin = table.Column<string>(type: "character varying(150)", maxLength: 150, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientCorsOrigins", x => x.Id);
table.ForeignKey(
name: "FK_ClientCorsOrigins_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientGrantTypes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
GrantType = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientGrantTypes", x => x.Id);
table.ForeignKey(
name: "FK_ClientGrantTypes_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientIdPRestrictions",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Provider = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientIdPRestrictions", x => x.Id);
table.ForeignKey(
name: "FK_ClientIdPRestrictions_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientPostLogoutRedirectUris",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
PostLogoutRedirectUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientPostLogoutRedirectUris", x => x.Id);
table.ForeignKey(
name: "FK_ClientPostLogoutRedirectUris_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ClientId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientProperties", x => x.Id);
table.ForeignKey(
name: "FK_ClientProperties_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientRedirectUris",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RedirectUri = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientRedirectUris", x => x.Id);
table.ForeignKey(
name: "FK_ClientRedirectUris_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientScopes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Scope = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientScopes", x => x.Id);
table.ForeignKey(
name: "FK_ClientScopes_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ClientSecrets",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ClientId = table.Column<int>(type: "integer", nullable: false),
Description = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
Value = table.Column<string>(type: "character varying(4000)", maxLength: 4000, nullable: false),
Expiration = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
Type = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClientSecrets", x => x.Id);
table.ForeignKey(
name: "FK_ClientSecrets_Clients_ClientId",
column: x => x.ClientId,
principalTable: "Clients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IdentityResourceClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
IdentityResourceId = table.Column<int>(type: "integer", nullable: false),
Type = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityResourceClaims", x => x.Id);
table.ForeignKey(
name: "FK_IdentityResourceClaims_IdentityResources_IdentityResourceId",
column: x => x.IdentityResourceId,
principalTable: "IdentityResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "IdentityResourceProperties",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
IdentityResourceId = table.Column<int>(type: "integer", nullable: false),
Key = table.Column<string>(type: "character varying(250)", maxLength: 250, nullable: false),
Value = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_IdentityResourceProperties", x => x.Id);
table.ForeignKey(
name: "FK_IdentityResourceProperties_IdentityResources_IdentityResour~",
column: x => x.IdentityResourceId,
principalTable: "IdentityResources",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ApiResourceClaims_ApiResourceId",
table: "ApiResourceClaims",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiResourceProperties_ApiResourceId",
table: "ApiResourceProperties",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiResources_Name",
table: "ApiResources",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ApiResourceScopes_ApiResourceId",
table: "ApiResourceScopes",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiResourceSecrets_ApiResourceId",
table: "ApiResourceSecrets",
column: "ApiResourceId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopeClaims_ScopeId",
table: "ApiScopeClaims",
column: "ScopeId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopeProperties_ScopeId",
table: "ApiScopeProperties",
column: "ScopeId");
migrationBuilder.CreateIndex(
name: "IX_ApiScopes_Name",
table: "ApiScopes",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ClientClaims_ClientId",
table: "ClientClaims",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientCorsOrigins_ClientId",
table: "ClientCorsOrigins",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientGrantTypes_ClientId",
table: "ClientGrantTypes",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientIdPRestrictions_ClientId",
table: "ClientIdPRestrictions",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientPostLogoutRedirectUris_ClientId",
table: "ClientPostLogoutRedirectUris",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientProperties_ClientId",
table: "ClientProperties",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientRedirectUris_ClientId",
table: "ClientRedirectUris",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_Clients_ClientId",
table: "Clients",
column: "ClientId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ClientScopes_ClientId",
table: "ClientScopes",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_ClientSecrets_ClientId",
table: "ClientSecrets",
column: "ClientId");
migrationBuilder.CreateIndex(
name: "IX_IdentityResourceClaims_IdentityResourceId",
table: "IdentityResourceClaims",
column: "IdentityResourceId");
migrationBuilder.CreateIndex(
name: "IX_IdentityResourceProperties_IdentityResourceId",
table: "IdentityResourceProperties",
column: "IdentityResourceId");
migrationBuilder.CreateIndex(
name: "IX_IdentityResources_Name",
table: "IdentityResources",
column: "Name",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApiResourceClaims");
migrationBuilder.DropTable(
name: "ApiResourceProperties");
migrationBuilder.DropTable(
name: "ApiResourceScopes");
migrationBuilder.DropTable(
name: "ApiResourceSecrets");
migrationBuilder.DropTable(
name: "ApiScopeClaims");
migrationBuilder.DropTable(
name: "ApiScopeProperties");
migrationBuilder.DropTable(
name: "ClientClaims");
migrationBuilder.DropTable(
name: "ClientCorsOrigins");
migrationBuilder.DropTable(
name: "ClientGrantTypes");
migrationBuilder.DropTable(
name: "ClientIdPRestrictions");
migrationBuilder.DropTable(
name: "ClientPostLogoutRedirectUris");
migrationBuilder.DropTable(
name: "ClientProperties");
migrationBuilder.DropTable(
name: "ClientRedirectUris");
migrationBuilder.DropTable(
name: "ClientScopes");
migrationBuilder.DropTable(
name: "ClientSecrets");
migrationBuilder.DropTable(
name: "IdentityResourceClaims");
migrationBuilder.DropTable(
name: "IdentityResourceProperties");
migrationBuilder.DropTable(
name: "ApiResources");
migrationBuilder.DropTable(
name: "ApiScopes");
migrationBuilder.DropTable(
name: "Clients");
migrationBuilder.DropTable(
name: "IdentityResources");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ namespace Yavsc.Services
{
private readonly ILogger _logger;
private Action<string, string> _errorHandler;
private Action<string, string>? _errorHandler;
/// <summary>
/// by cx id

View File

@ -1,37 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Yavsc.Models;
using IdentityServer8.Stores;
using IdentityServer8.Models;
namespace Yavsc.Services;
public class ClientStore : IClientStore
{
public ClientStore(ApplicationDbContext applicationDbContext)
{
ApplicationDbContext = applicationDbContext;
}
public ApplicationDbContext ApplicationDbContext { get; }
public async Task<Client> FindClientByIdAsync(string clientId)
{
var clientFromDb = await ApplicationDbContext.Client.FirstOrDefaultAsync(c => c.Id == clientId);
if (clientFromDb == null) return null;
return new Client
{
ClientId = clientFromDb.Id,
ClientName = clientFromDb.DisplayName,
ClientSecrets = { new Secret(clientFromDb.Secret.Sha256()) },
AllowedGrantTypes =
[
GrantType.AuthorizationCode,
GrantType.DeviceFlow,
GrantType.ClientCredentials
],
AllowedScopes = ["openid", "profile", "scope1"],
AbsoluteRefreshTokenLifetime = clientFromDb.RefreshTokenLifeTime,
AccessTokenLifetime = clientFromDb.AccessTokenLifetime
};
}
}

View File

@ -11,54 +11,62 @@
<h4>Client</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ClientId" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="ClientId" class="form-control" />
<span asp-validation-for="ClientId" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<input asp-for="Active" />
<label asp-for="Active"></label>
<input asp-for="Enabled" />
<label asp-for="Enabled"></label>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="DisplayName" class="col-md-2 control-label"></label>
<label asp-for="ClientName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="DisplayName" class="form-control" />
<span asp-validation-for="DisplayName" class="text-danger" ></span>
<input asp-for="ClientName" class="form-control" />
<span asp-validation-for="ClientName" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="LogoutRedirectUri" class="col-md-2 control-label"></label>
<label asp-for="FrontChannelLogoutUri" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="LogoutRedirectUri" class="form-control"></span>
<span asp-validation-for="LogoutRedirectUri" class="text-danger" ></span>
<input asp-for="FrontChannelLogoutUri" class="form-control"></span>
<span asp-validation-for="FrontChannelLogoutUri" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="RedirectUri" class="col-md-2 control-label"></label>
<label asp-for="RedirectUris" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="RedirectUri" class="form-control" />
<span asp-validation-for="RedirectUri" class="text-danger" ></span>
<input asp-for="RedirectUris" class="form-control" />
<span asp-validation-for="RedirectUris" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="RefreshTokenLifeTime" class="col-md-2 control-label"></label>
<label asp-for="AbsoluteRefreshTokenLifetime" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="RefreshTokenLifeTime" class="form-control" ></span>
<span asp-validation-for="RefreshTokenLifeTime" class="text-danger"></span>
<input asp-for="AbsoluteRefreshTokenLifetime" class="form-control" ></span>
<span asp-validation-for="AbsoluteRefreshTokenLifetime" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Secret" class="col-md-2 control-label"></label>
<label asp-for="ClientSecrets" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Secret" class="form-control" />
<span asp-validation-for="Secret" class="text-danger" ></span>
<input asp-for="ClientSecrets" class="form-control" />
<span asp-validation-for="ClientSecrets" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="Type" class="col-md-2 control-label"></label>
<label asp-for="AccessTokenType" class="col-md-2 control-label"></label>
<div class="col-md-10">
@Html.DropDownList("Type")
<span asp-validation-for="Type" class="text-danger"></span>
@Html.DropDownList("AccessTokenType")
<span asp-validation-for="AccessTokenType" class="text-danger"></span>
</div>
</div>
<div class="form-group">

View File

@ -12,46 +12,52 @@
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Active)
@Html.DisplayNameFor(model => model.ClientId)
</dt>
<dt>
@Html.DisplayNameFor(model => model.ClientId)
</dt>
<dt>
@Html.DisplayNameFor(model => model.Enabled)
</dt>
<dt>
@Html.DisplayNameFor(model => model.Enabled)
</dt>
<dt>
@Html.DisplayNameFor(model => model.ClientName)
</dt>
<dd>
@Html.DisplayFor(model => model.Active)
@Html.DisplayFor(model => model.ClientName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.DisplayName)
@Html.DisplayNameFor(model => model.FrontChannelLogoutUri)
</dt>
<dd>
@Html.DisplayFor(model => model.DisplayName)
@Html.DisplayFor(model => model.FrontChannelLogoutUri)
</dd>
<dt>
@Html.DisplayNameFor(model => model.LogoutRedirectUri)
@Html.DisplayNameFor(model => model.RedirectUris)
</dt>
<dd>
@Html.DisplayFor(model => model.LogoutRedirectUri)
@Html.DisplayFor(model => model.RedirectUris)
</dd>
<dt>
@Html.DisplayNameFor(model => model.RedirectUri)
@Html.DisplayNameFor(model => model.AbsoluteRefreshTokenLifetime)
</dt>
<dd>
@Html.DisplayFor(model => model.RedirectUri)
@Html.DisplayFor(model => model.AbsoluteRefreshTokenLifetime)
</dd>
<dt>
@Html.DisplayNameFor(model => model.RefreshTokenLifeTime)
@Html.DisplayNameFor(model => model.ClientSecrets)
</dt>
<dd>
@Html.DisplayFor(model => model.RefreshTokenLifeTime)
@Html.DisplayFor(model => model.ClientSecrets)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Secret)
@Html.DisplayNameFor(model => model.AccessTokenType)
</dt>
<dd>
@Html.DisplayFor(model => model.Secret)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Type)
</dt>
<dd>
@Html.DisplayFor(model => model.Type)
@Html.DisplayFor(model => model.AccessTokenType)
</dd>
</dl>

View File

@ -11,52 +11,54 @@
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Id)
@Html.DisplayNameFor(model => model.ClientId)
</dt>
<dd>
@Html.DisplayFor(model => model.Id)
@Html.DisplayFor(model => model.ClientId)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Active)
@Html.DisplayNameFor(model => model.Enabled)
</dt>
<dd>
@Html.DisplayFor(model => model.Active)
@Html.DisplayFor(model => model.Enabled)
</dd>
<dt>
@Html.DisplayNameFor(model => model.DisplayName)
@Html.DisplayNameFor(model => model.ClientName)
</dt>
<dd>
@Html.DisplayFor(model => model.DisplayName)
@Html.DisplayFor(model => model.ClientName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.LogoutRedirectUri)
@Html.DisplayNameFor(model => model.FrontChannelLogoutUri)
</dt>
<dd>
@Html.DisplayFor(model => model.LogoutRedirectUri)
@Html.DisplayFor(model => model.FrontChannelLogoutUri)
</dd>
<dt>
@Html.DisplayNameFor(model => model.RedirectUri)
@Html.DisplayNameFor(model => model.RedirectUris)
</dt>
<dd>
@Html.DisplayFor(model => model.RedirectUri)
<ul>
@foreach (var uri in Model.RedirectUris)
{ <li>@uri.RedirectUri</li> }
</ul>
</dd>
<dt>
@Html.DisplayNameFor(model => model.RefreshTokenLifeTime)
@Html.DisplayNameFor(model => model.AbsoluteRefreshTokenLifetime)
</dt>
<dd>
@Html.DisplayFor(model => model.RefreshTokenLifeTime)
@Html.DisplayFor(model => model.AbsoluteRefreshTokenLifetime)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Secret)
@Html.DisplayNameFor(model => model.ClientSecrets)
</dt>
<dd>
@Html.DisplayFor(model => model.Secret)
</dd>
<dd>Count : @Model.ClientSecrets.Count</dd>
<dt>
@Html.DisplayNameFor(model => model.Type)
@Html.DisplayNameFor(model => model.AccessTokenType)
</dt>
<dd>
@Html.DisplayFor(model => model.Type)
@Html.DisplayFor(model => model.AccessTokenType)
</dd>
</dl>
</div>

View File

@ -11,55 +11,62 @@
<h4>Client</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<input type="hidden" asp-for="ClientId" />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<input asp-for="Active" />
<label asp-for="Active"></label>
<input asp-for="Enabled" />
<label asp-for="Enabled"></label>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="DisplayName" class="col-md-2 control-label"></label>
<label asp-for="ClientName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="DisplayName" class="form-control" />
<span asp-validation-for="DisplayName" class="text-danger" ></span>
<input asp-for="ClientName" class="form-control" />
<span asp-validation-for="ClientName" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="LogoutRedirectUri" class="col-md-2 control-label"></label>
<label asp-for="FrontChannelLogoutUri" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="LogoutRedirectUri" class="form-control" />
<span asp-validation-for="LogoutRedirectUri" class="text-danger" ></span>
<input asp-for="FrontChannelLogoutUri" class="form-control" />
<span asp-validation-for="FrontChannelLogoutUri" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="RedirectUri" class="col-md-2 control-label"></label>
<label asp-for="RedirectUris" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="RedirectUri" class="form-control" />
<span asp-validation-for="RedirectUri" class="text-danger" ></span>
<input asp-for="RedirectUris" class="form-control" />
<span asp-validation-for="RedirectUris" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="RefreshTokenLifeTime" class="col-md-2 control-label"></label>
<label asp-for="IdentityTokenLifetime" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="RefreshTokenLifeTime" class="form-control" />
<span asp-validation-for="RefreshTokenLifeTime" class="text-danger" ></span>
<input asp-for="IdentityTokenLifetime" class="form-control" />
<span asp-validation-for="IdentityTokenLifetime" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="Secret" class="col-md-2 control-label"></label>
<label asp-for="AbsoluteRefreshTokenLifetime" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Secret" class="form-control" />
<span asp-validation-for="Secret" class="text-danger" ></span>
<input asp-for="AbsoluteRefreshTokenLifetime" class="form-control" />
<span asp-validation-for="AbsoluteRefreshTokenLifetime" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="Type" class="col-md-2 control-label"></label>
<label asp-for="ClientSecrets" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="ClientSecrets" class="form-control" />
<span asp-validation-for="ClientSecrets" class="text-danger" ></span>
</div>
</div>
<div class="form-group">
<label asp-for="AccessTokenType" class="col-md-2 control-label"></label>
<div class="col-md-10">
@Html.DropDownList("Type")
<span asp-validation-for="Type" class="text-danger" ></span>
<span asp-validation-for="AccessTokenType" class="text-danger" ></span>
</div>
</div>
<div class="form-group">

View File

@ -1,4 +1,5 @@
@model IEnumerable<Client>
@using IdentityServer8.Models
@model IEnumerable<IdentityServer8.EntityFramework.Entities.Client>
@{
ViewData["Title"] = @SR["Index"];
@ -12,25 +13,28 @@
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Active)
@Html.DisplayNameFor(model => model.ClientId)
</th>
<th>
@Html.DisplayNameFor(model => model.DisplayName)
@Html.DisplayNameFor(model => model.Enabled)
</th>
<th>
@Html.DisplayNameFor(model => model.LogoutRedirectUri)
@Html.DisplayNameFor(model => model.ClientName)
</th>
<th>
@Html.DisplayNameFor(model => model.RedirectUri)
@Html.DisplayNameFor(model => model.FrontChannelLogoutUri)
</th>
<th>
@Html.DisplayNameFor(model => model.RefreshTokenLifeTime)
@Html.DisplayNameFor(model => model.RedirectUris)
</th>
<th>
@Html.DisplayNameFor(model => model.Secret)
@Html.DisplayNameFor(model => model.AbsoluteRefreshTokenLifetime)
</th>
<th>
@Html.DisplayNameFor(model => model.Type)
@Html.DisplayNameFor(model => model.AllowedGrantTypes)
</th>
<th>
@Html.DisplayNameFor(model => model.AccessTokenType)
</th>
<th></th>
</tr>
@ -38,30 +42,39 @@
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Active)
@Html.DisplayFor(modelItem => item.ClientId)
</td>
<td>
@Html.DisplayFor(modelItem => item.DisplayName)
@Html.DisplayFor(modelItem => item.Enabled)
</td>
<td>
@Html.DisplayFor(modelItem => item.LogoutRedirectUri)
@Html.DisplayFor(modelItem => item.ClientName)
</td>
<td>
@Html.DisplayFor(modelItem => item.RedirectUri)
@Html.DisplayFor(modelItem => item.FrontChannelLogoutUri)
</td>
<td>
@Html.DisplayFor(modelItem => item.RefreshTokenLifeTime)
<ul>
@foreach (var uri in item.RedirectUris)
{ <li>@uri.RedirectUri</li> }
</ul>
</td>
<td>
@Html.DisplayFor(modelItem => item.Secret)
@Html.DisplayFor(modelItem => item.AbsoluteRefreshTokenLifetime)
</td>
<td>
@Html.DisplayFor(modelItem => item.Type)
<ul>
@foreach (var t in item.AllowedGrantTypes)
{ <li>@t.GrantType</li> }
</ul>
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
@Enum.GetName(typeof(AccessTokenType), item.AccessTokenType)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.ClientId">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ClientId">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ClientId">Delete</a>
</td>
</tr>
}

View File

@ -31,6 +31,7 @@
@using Yavsc.Helpers;
@using Yavsc.Server.Helpers;
@using PayPal.PayPalAPIInterfaceService.Model;
@using IdentityServer8.EntityFramework.Entities;
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Yavsc

View File

@ -15,6 +15,10 @@
</PackageReference>
<PackageReference Include="HigginsSoft.IdentityServer8" />
<PackageReference Include="HigginsSoft.IdentityServer8.AspNetIdentity" />
<PackageReference Include="HigginsSoft.IdentityServer8.EntityFramework" />
<PackageReference Include="HigginsSoft.IdentityServer8.EntityFramework.Storage" />
<PackageReference Include="HigginsSoft.IdentityServer8.Security" />
<PackageReference Include="HigginsSoft.IdentityServer8.Storage" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" />

View File

@ -123,32 +123,7 @@ namespace isnd.tests
TestClientId = "testClientId";
TestingUser = await dbContext.Users.FirstOrDefaultAsync(u => u.UserName == TestingUserName);
EnsureUser(TestingUserName, TestingUserPassword);
// ensure a client
var testClient = await dbContext.Client.FirstOrDefaultAsync((c) => c.Id == TestClientId);
if (testClient == null)
{
testClient = new Yavsc.Models.Auth.Client
{
Id = TestClientId,
DisplayName = "Testing Client",
Secret = TestClientSecret,
Active = true,
Type = ApplicationTypes.NativeConfidential,
AccessTokenLifetime = 900,
RefreshTokenLifeTime = 15000
};
dbContext.Client.Add(testClient);
dbContext.SaveChanges();
}
else
{
testClient.DisplayName = "Testing Client";
testClient.Secret = TestClientSecret;
testClient.Active = true;
testClient.Type = ApplicationTypes.NativeConfidential;
testClient.AccessTokenLifetime = 900;
testClient.RefreshTokenLifeTime = 1500;
}
}
public void EnsureUser(string testingUserName, string password)