diff --git a/src/Yavsc.Org/Controllers/Administration/ApiScopeController.cs b/src/Yavsc.Org/Controllers/Administration/ApiScopeController.cs new file mode 100644 index 00000000..0a32abaf --- /dev/null +++ b/src/Yavsc.Org/Controllers/Administration/ApiScopeController.cs @@ -0,0 +1,153 @@ + +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Yavsc.Models; +using IdentityServer8.EntityFramework.Entities; +namespace Yavsc.Org.Controllers +{ + public class ApiScopeController : Controller + { + private readonly ApplicationDbContext _context; + + public ApiScopeController(ApplicationDbContext context) + { + _context = context; + } + + // GET: ApiScope + public async Task Index() + { + return View(await _context.ApiScopes.ToListAsync()); + } + + // GET: ApiScope/Details/5 + public async Task Details(int? id) + { + if (id == null) + { + return NotFound(); + } + + var apiScope = await _context.ApiScopes + .FirstOrDefaultAsync(m => m.Id == id); + if (apiScope == null) + { + return NotFound(); + } + + return View(apiScope); + } + + // GET: ApiScope/Create + public IActionResult Create() + { + return View(); + } + + // POST: ApiScope/Create + // To protect from overposting attacks, enable the specific properties you want to bind to. + // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598. + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Create(ApiScope apiScope) + { + if (ModelState.IsValid) + { + _context.Add(apiScope); + await _context.SaveChangesAsync(); + return RedirectToAction(nameof(Index)); + } + return View(apiScope); + } + + // GET: ApiScope/Edit/5 + public async Task Edit(int? id) + { + if (id == null) + { + return NotFound(); + } + + var apiScope = await _context.ApiScopes.FindAsync(id); + if (apiScope == null) + { + return NotFound(); + } + return View(apiScope); + } + + // POST: ApiScope/Edit/5 + // To protect from overposting attacks, enable the specific properties you want to bind to. + // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598. + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Edit(int id, + ApiScope apiScope) + { + if (id != apiScope.Id) + { + return NotFound(); + } + + if (ModelState.IsValid) + { + try + { + _context.Update(apiScope); + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!ApiScopeExists(apiScope.Id)) + { + return NotFound(); + } + else + { + throw; + } + } + return RedirectToAction(nameof(Index)); + } + return View(apiScope); + } + + // GET: ApiScope/Delete/5 + public async Task Delete(int? id) + { + if (id == null) + { + return NotFound(); + } + + var apiScope = await _context.ApiScopes + .FirstOrDefaultAsync(m => m.Id == id); + if (apiScope == null) + { + return NotFound(); + } + + return View(apiScope); + } + + // POST: ApiScope/Delete/5 + [HttpPost, ActionName("Delete")] + [ValidateAntiForgeryToken] + public async Task DeleteConfirmed(int id) + { + var apiScope = await _context.ApiScopes.FindAsync(id); + if (apiScope != null) + { + _context.ApiScopes.Remove(apiScope); + } + + await _context.SaveChangesAsync(); + return RedirectToAction(nameof(Index)); + } + + private bool ApiScopeExists(int id) + { + return _context.ApiScopes.Any(e => e.Id == id); + } + } +} diff --git a/src/Yavsc.Org/Controllers/Administration/ApiScopesApiController.cs b/src/Yavsc.Org/Controllers/Administration/ApiScopesApiController.cs new file mode 100644 index 00000000..983e7233 --- /dev/null +++ b/src/Yavsc.Org/Controllers/Administration/ApiScopesApiController.cs @@ -0,0 +1,58 @@ +using IdentityServer8.EntityFramework.Entities; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Yavsc.Models; +using Yavsc.Server.Helpers; + +namespace Yavsc.Org.Controllers.Administration +{ + [Route("api/[controller]")] + [ApiController] + public class ApiScopesApiController : ControllerBase + { + private ApplicationDbContext dbContext; + + public ApiScopesApiController(ApplicationDbContext dbContext) + { + this.dbContext = dbContext; + } + // GET: api/ + [HttpGet] + public async Task> Get(int skip = 0, int take = 25) + { + return await dbContext.ApiScopes.Skip(skip).Take(take).ToArrayAsync(); + } + + // GET api//5 + [HttpGet("{id}")] + public async Task Get(int id) + { + return await dbContext.ApiScopes.FirstOrDefaultAsync(s => s.Id == id); + } + + // POST api/ + [HttpPost] + public async Task Post([FromBody] ApiScope value) + { + dbContext.ApiScopes.Add(value); + await dbContext.SaveChangesAsync(User.GetUserId()); + } + + // PUT api//5 + [HttpPut("{id}")] + public async Task Put(int id, [FromBody] ApiScope value) + { + dbContext.Update(value); + await dbContext.SaveChangesAsync(User.GetUserId()); + } + + // DELETE api//5 + [HttpDelete("{id}")] + public async Task Delete(int id) + { + var scope = await dbContext.ApiScopes.FirstAsync(s => s.Id == id); + dbContext.Remove(scope); + } + } +} diff --git a/src/Yavsc.Org/Controllers/Administration/ClientController.cs b/src/Yavsc.Org/Controllers/Administration/ClientController.cs index 47a6c0aa..658a7639 100644 --- a/src/Yavsc.Org/Controllers/Administration/ClientController.cs +++ b/src/Yavsc.Org/Controllers/Administration/ClientController.cs @@ -5,33 +5,36 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; using Yavsc.Models; using Yavsc.Models.Auth; +using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Authorize("AdministratorOnly")] public class ClientController : Controller { - private readonly ApplicationDbContext context; + private readonly ApplicationDbContext dbContext; private readonly ClientStore clientStore; + private readonly SiteSettings siteSettings; - public ClientController(ApplicationDbContext context, - ClientStore clientStore, - - IdentityServer8.Stores.ValidatingClientStore validatingClientStore + public ClientController( + ApplicationDbContext dbContext, + ClientStore clientStore, IOptions siteSettingsOptions ) { - this.context = context; + this.dbContext = dbContext; this.clientStore = clientStore; + this.siteSettings = siteSettingsOptions.Value; } // GET: Client public async Task Index() { - return View(await context.Clients.Include(c => c.AllowedGrantTypes) + return View(await dbContext.Clients.Include(c => c.AllowedGrantTypes) .Include(c => c.RedirectUris).ToListAsync()); } @@ -39,7 +42,7 @@ namespace Yavsc.Controllers public async Task Details(int id) { - Client client = await context.Clients.Include( + Client client = await dbContext.Clients.Include( c => c.ClientSecrets ).Include(c => c.AllowedGrantTypes) .Include(c => c.RedirectUris) @@ -59,8 +62,6 @@ namespace Yavsc.Controllers // GET: Client/Create public IActionResult Create() { - Secret s; - SetAppTypesInputValues(); return View(); } @@ -68,6 +69,7 @@ namespace Yavsc.Controllers // POST: Client/Create [HttpPost] [ValidateAntiForgeryToken] + public async Task Create(Client client) { if (ModelState.IsValid) @@ -79,16 +81,39 @@ namespace Yavsc.Controllers return BadRequest(ModelState); } - context.Clients.Add(client); - if (client.ClientSecrets != null) - { - foreach (var secret in client.ClientSecrets) - { - context.ClientSecrets.Add(secret); - } - } - await context.SaveChangesAsync(); + dbContext.Clients.Add(client); + await dbContext.SaveChangesAsync(User.GetUserId()); + dbContext.ClientRedirectUris.Add(new ClientRedirectUri + { + ClientId = client.Id, + RedirectUri = siteSettings.Audience + + }); + dbContext.ClientCorsOrigins.Add(new ClientCorsOrigin + { + ClientId = client.Id, + Origin = siteSettings.Audience + + }); + foreach (String credType in new String[] { "code", "client_credentials", "password" }) + { + dbContext.ClientGrantTypes.Add(new ClientGrantType + { + ClientId = client.Id, + GrantType = credType + }); + } + foreach (String scope in new String[] { "openid", "profile" }) + { + dbContext.ClientScopes.Add(new ClientScope + { + ClientId = client.Id, + Scope = scope + }); + } + + await dbContext.SaveChangesAsync(User.GetUserId()); return RedirectToAction("Index"); } @@ -112,7 +137,7 @@ namespace Yavsc.Controllers // GET: Client/Edit/5 public async Task Edit(int id) { - Client client = await context.Clients.SingleOrDefaultAsync(m => m.Id == id); + Client client = await dbContext.Clients.SingleOrDefaultAsync(m => m.Id == id); if (client == null) { return NotFound(); @@ -133,11 +158,11 @@ namespace Yavsc.Controllers { foreach (var secret in client.ClientSecrets) { - context.Update(secret); + dbContext.Update(secret); } } - context.Update(client); - await context.SaveChangesAsync(); + dbContext.Update(client); + await dbContext.SaveChangesAsync(); return RedirectToAction("Index"); } return View(client); @@ -148,7 +173,7 @@ namespace Yavsc.Controllers public async Task Delete(int id) { - Client client = await context.Clients.SingleOrDefaultAsync(m => m.Id == id); + Client client = await dbContext.Clients.SingleOrDefaultAsync(m => m.Id == id); if (client == null) { return NotFound(); @@ -162,11 +187,11 @@ namespace Yavsc.Controllers [ValidateAntiForgeryToken] public async Task DeleteConfirmed(int id) { - Client client = await context.Clients + Client client = await dbContext.Clients .Include(client => client.ClientSecrets) .SingleAsync(m => m.Id == id); - context.Clients.Remove(client); - await context.SaveChangesAsync(); + dbContext.Clients.Remove(client); + await dbContext.SaveChangesAsync(); return RedirectToAction("Index"); } } diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index 73408301..4af832b0 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -43,6 +43,7 @@ using IdentityServer8.EntityFramework.Services; using IdentityServer8.EntityFramework.Interfaces; using Microsoft.AspNetCore.Authentication.Cookies; using IdentityServer8.Validation; +using IdentityServer8.EntityFramework.Entities; namespace Yavsc.Extensions; @@ -288,7 +289,20 @@ public static class HostingExtensions .AddConfigurationStore(options => { options.ConfigureDbContext = b => b.UseNpgsql(connectionString, - sql => sql.MigrationsAssembly(migrationsAssembly)); + sql => sql.MigrationsAssembly(migrationsAssembly)) + .UseSeeding((context, _) => + { + foreach (String scope in new string[] { "blog", "admin", "contract", "com"}) + { + var testBlog = context.Set().FirstOrDefault(b => b.Name == scope); + if (testBlog == null) + { + context.Set().Add(new ApiScope { Name = scope }); + context.SaveChanges(); + } + } + + }); }) .AddOperationalStore(options => { @@ -398,7 +412,7 @@ public static class HostingExtensions app.UseSession(); return app; } - + private static void MigrateDatabase(this IApplicationBuilder app) { using (var serviceScope = app.ApplicationServices.GetRequiredService().CreateScope()) diff --git a/src/Yavsc.Org/Views/ApiScope/Create.cshtml b/src/Yavsc.Org/Views/ApiScope/Create.cshtml new file mode 100644 index 00000000..5d3b9b8b --- /dev/null +++ b/src/Yavsc.Org/Views/ApiScope/Create.cshtml @@ -0,0 +1,69 @@ +@model IdentityServer8.EntityFramework.Entities.ApiScope + +@{ + Layout = null; +} + + + + + + + Create + + + +

ApiScope

+
+
+
+
+
+
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + + + + diff --git a/src/Yavsc.Org/Views/ApiScope/Delete.cshtml b/src/Yavsc.Org/Views/ApiScope/Delete.cshtml new file mode 100644 index 00000000..166e6110 --- /dev/null +++ b/src/Yavsc.Org/Views/ApiScope/Delete.cshtml @@ -0,0 +1,72 @@ +@model Yavsc.Models.YavscApiScope + +@{ + Layout = null; +} + + + + + + + Delete + + + +

Are you sure you want to delete this?

+
+

YavscApiScope

+
+
+
+ @Html.DisplayNameFor(model => model.Enabled) +
+
+ @Html.DisplayFor(model => model.Enabled) +
+
+ @Html.DisplayNameFor(model => model.Name) +
+
+ @Html.DisplayFor(model => model.Name) +
+
+ @Html.DisplayNameFor(model => model.DisplayName) +
+
+ @Html.DisplayFor(model => model.DisplayName) +
+
+ @Html.DisplayNameFor(model => model.Description) +
+
+ @Html.DisplayFor(model => model.Description) +
+
+ @Html.DisplayNameFor(model => model.Required) +
+
+ @Html.DisplayFor(model => model.Required) +
+
+ @Html.DisplayNameFor(model => model.Emphasize) +
+
+ @Html.DisplayFor(model => model.Emphasize) +
+
+ @Html.DisplayNameFor(model => model.ShowInDiscoveryDocument) +
+
+ @Html.DisplayFor(model => model.ShowInDiscoveryDocument) +
+
+ +
+ + | + Back to List +
+
+ + diff --git a/src/Yavsc.Org/Views/ApiScope/Details.cshtml b/src/Yavsc.Org/Views/ApiScope/Details.cshtml new file mode 100644 index 00000000..6c904ce3 --- /dev/null +++ b/src/Yavsc.Org/Views/ApiScope/Details.cshtml @@ -0,0 +1,69 @@ +@model Yavsc.Models.YavscApiScope + +@{ + Layout = null; +} + + + + + + + Details + + + +
+

YavscApiScope

+
+
+
+ @Html.DisplayNameFor(model => model.Enabled) +
+
+ @Html.DisplayFor(model => model.Enabled) +
+
+ @Html.DisplayNameFor(model => model.Name) +
+
+ @Html.DisplayFor(model => model.Name) +
+
+ @Html.DisplayNameFor(model => model.DisplayName) +
+
+ @Html.DisplayFor(model => model.DisplayName) +
+
+ @Html.DisplayNameFor(model => model.Description) +
+
+ @Html.DisplayFor(model => model.Description) +
+
+ @Html.DisplayNameFor(model => model.Required) +
+
+ @Html.DisplayFor(model => model.Required) +
+
+ @Html.DisplayNameFor(model => model.Emphasize) +
+
+ @Html.DisplayFor(model => model.Emphasize) +
+
+ @Html.DisplayNameFor(model => model.ShowInDiscoveryDocument) +
+
+ @Html.DisplayFor(model => model.ShowInDiscoveryDocument) +
+
+
+ + + diff --git a/src/Yavsc.Org/Views/ApiScope/Edit.cshtml b/src/Yavsc.Org/Views/ApiScope/Edit.cshtml new file mode 100644 index 00000000..34b111d4 --- /dev/null +++ b/src/Yavsc.Org/Views/ApiScope/Edit.cshtml @@ -0,0 +1,70 @@ +@model Yavsc.Models.YavscApiScope + +@{ + Layout = null; +} + + + + + + + Edit + + + +

YavscApiScope

+
+
+
+
+
+ +
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + + + + diff --git a/src/Yavsc.Org/Views/ApiScope/Index.cshtml b/src/Yavsc.Org/Views/ApiScope/Index.cshtml new file mode 100644 index 00000000..2d3bd6c7 --- /dev/null +++ b/src/Yavsc.Org/Views/ApiScope/Index.cshtml @@ -0,0 +1,79 @@ +@model IEnumerable + +@{ + Layout = null; +} + + + + + + + Index + + +

+ Create New +

+ + + + + + + + + + + + + + +@foreach (var item in Model) { + + + + + + + + + + +} + +
+ @Html.DisplayNameFor(model => model.Enabled) + + @Html.DisplayNameFor(model => model.Name) + + @Html.DisplayNameFor(model => model.DisplayName) + + @Html.DisplayNameFor(model => model.Description) + + @Html.DisplayNameFor(model => model.Required) + + @Html.DisplayNameFor(model => model.Emphasize) + + @Html.DisplayNameFor(model => model.ShowInDiscoveryDocument) +
+ @Html.DisplayFor(modelItem => item.Enabled) + + @Html.DisplayFor(modelItem => item.Name) + + @Html.DisplayFor(modelItem => item.DisplayName) + + @Html.DisplayFor(modelItem => item.Description) + + @Html.DisplayFor(modelItem => item.Required) + + @Html.DisplayFor(modelItem => item.Emphasize) + + @Html.DisplayFor(modelItem => item.ShowInDiscoveryDocument) + + Edit | + Details | + Delete +
+ + diff --git a/src/Yavsc.Org/Views/Client/Details.cshtml b/src/Yavsc.Org/Views/Client/Details.cshtml index 6b36252b..b86615a4 100644 --- a/src/Yavsc.Org/Views/Client/Details.cshtml +++ b/src/Yavsc.Org/Views/Client/Details.cshtml @@ -60,7 +60,7 @@ @Html.DisplayNameFor(model => model.AccessTokenType)
- @Html.DisplayFor(model => model.AccessTokenType) + @Html.DisplayFor(model => model.AccessTokenType)
diff --git a/src/Yavsc.Org/Views/Client/Index.cshtml b/src/Yavsc.Org/Views/Client/Index.cshtml index 557631f9..f91f71dc 100644 --- a/src/Yavsc.Org/Views/Client/Index.cshtml +++ b/src/Yavsc.Org/Views/Client/Index.cshtml @@ -1,4 +1,4 @@ -@using IdentityServer8.Models +@using IdentityServer8.Models; @model IEnumerable

@Localizer["Index"]

@@ -7,77 +7,85 @@ @Localizer["Create New"]

- - - - - - - - - - - - - - @foreach (var item in Model) - { - - - - - - - - - - - - } -
- @Html.DisplayNameFor(model => model.ClientId) - - @Html.DisplayNameFor(model => model.Enabled) - - @Html.DisplayNameFor(model => model.ClientName) - - @Html.DisplayNameFor(model => model.FrontChannelLogoutUri) - - @Html.DisplayNameFor(model => model.RedirectUris) - - @Html.DisplayNameFor(model => model.AbsoluteRefreshTokenLifetime) - - @Html.DisplayNameFor(model => model.AllowedGrantTypes) - - @Html.DisplayNameFor(model => model.AccessTokenType) -
- @Html.DisplayFor(modelItem => item.ClientId) - - @Html.DisplayFor(modelItem => item.Enabled) - +@foreach (var item in Model) +{ +
+ +
+
Identifier
+
and activation
+
+ +
+ @Html.DisplayNameFor(modelItem => item.ClientName) +
+
@Html.DisplayFor(modelItem => item.ClientName) -
- @Html.DisplayFor(modelItem => item.FrontChannelLogoutUri) - -
    - @foreach (var uri in item.RedirectUris) - { -
  • @uri.RedirectUri
  • - } -
-
- @Html.DisplayFor(modelItem => item.AbsoluteRefreshTokenLifetime) - -
    - @foreach (var t in item.AllowedGrantTypes) - { -
  • @t.GrantType
  • - } -
-
+ +
+ @Html.DisplayNameFor(modelItem => item.ClientId) +
+
+ @Html.DisplayFor(modelItem => item.ClientId) +
+
+ @Html.DisplayNameFor(modelItem => item.Enabled) +
+
+ @Html.DisplayFor(modelItem => item.Enabled) +
+ + + +
+ +
Urls
+
login and logout, refresh token
+
+
+ @Html.DisplayNameFor(model => model.FrontChannelLogoutUri) +
+
@Html.DisplayFor(model => item.FrontChannelLogoutUri) +
+
@Html.DisplayNameFor(model => model.RedirectUris)
+
+ @foreach (var uri in item.RedirectUris) + { +
  • @uri.RedirectUri
  • + } +
    +
    @Html.DisplayNameFor(model => model.AbsoluteRefreshTokenLifetime)
    +
    @Html.DisplayFor(model => item.AbsoluteRefreshTokenLifetime)
    + +
    +
    + +
    + +
    Grants
    +
    and access type
    + +
    +
    @Html.DisplayNameFor(model => model.AllowedGrantTypes)
    +
    @foreach (var t in item.AllowedGrantTypes) + { +
  • @t.GrantType
  • + } +
    + +
    + @Html.DisplayNameFor(model => model.AccessTokenType) +
    +
    @Enum.GetName(typeof(AccessTokenType), item.AccessTokenType) -
    - Edit | - Details | - Delete -
    + + + + + + Edit + Details + Delete + + +} diff --git a/src/Yavsc.Org/Views/Shared/_Layout.cshtml b/src/Yavsc.Org/Views/Shared/_Layout.cshtml index aaf974a7..45f6e976 100644 --- a/src/Yavsc.Org/Views/Shared/_Layout.cshtml +++ b/src/Yavsc.Org/Views/Shared/_Layout.cshtml @@ -8,7 +8,7 @@ - + @@ -36,7 +36,7 @@ background-attachment: fixed; } } @await RenderSectionAsync("subbanner", false) -
    +
    @RenderBody()