broken/ef
Paul Schneider 3 years ago
parent 749eb645d5
commit dd6d83cf06
28 changed files with 1097 additions and 184 deletions

@ -13,12 +13,6 @@ using System.Threading.Tasks;
namespace nuget_host.Controllers
{
/// <summary>
/// This sample controller implements a typical login/logout/provision workflow for local and external accounts.
/// The login service encapsulates the interactions with the user data store. This data store is in-memory only and cannot be used for production!
/// The interaction service provides a way for the UI to communicate with identityserver for validation and context retrieval
/// </summary>
[SecurityHeaders]
[AllowAnonymous]
public class AccountController : Controller
{

@ -0,0 +1,146 @@
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using nuget_host.Data;
using nuget_host.Entities;
using nuget_host.Models;
using nuget_host.Models.ApiKeys;
namespace nuget_host.Controllers
{
[Authorize]
public class ApiKeysController : Controller
{
private readonly ApplicationDbContext dbContext;
private readonly NugetSettings nugetSettings;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IDataProtector protector;
public ApiKeysController(ApplicationDbContext dbContext,
IOptions<NugetSettings> nugetSettingsOptions,
IDataProtectionProvider provider,
UserManager<ApplicationUser> userManager)
{
this.dbContext = dbContext;
this.nugetSettings = nugetSettingsOptions.Value;
protector = provider.CreateProtector(nugetSettings.ProtectionTitle);
_userManager = userManager;
}
[HttpGet]
public async Task<ActionResult> Index()
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
System.Collections.Generic.List<ApiKey> index = GetUserKeys().ToList();
IndexModel model = new IndexModel { ApiKey = index };
ViewData["Title"] = "Index";
return View("Index", model);
}
[HttpGet]
public async Task<ActionResult> Create()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var username = User.Identity.Name;
var user = await _userManager.FindByIdAsync(userId);
ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
return View(new CreateModel{ });
}
[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
IQueryable<ApiKey> userKeys = GetUserKeys();
if (userKeys.Count() >= nugetSettings.MaxUserKeyCount)
{
ModelState.AddModelError(null, "Maximum key count reached");
return View();
}
ApiKey newKey = new ApiKey { UserId = userid, Name = model.Name };
_ = dbContext.ApiKeys.Add(newKey);
_ = await dbContext.SaveChangesAsync();
return View("Details", new DetailModel { Name = newKey.Name,
ProtectedValue = protector.Protect(newKey.Id),
ApiKey = newKey });
}
[HttpGet]
public async Task<ActionResult> Delete(string id)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApiKey key = dbContext.ApiKeys.FirstOrDefault(k => k.Id == id && k.UserId == userid);
return View(new DeleteModel { ApiKey = key });
}
[HttpPost]
public async Task<ActionResult> Delete(DeleteModel model)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApiKey key = dbContext.ApiKeys.FirstOrDefault(k => k.Id == model.ApiKey.Id && k.UserId == userid);
if (key == null)
{
ModelState.AddModelError(null, "Key not found");
return View();
}
_ = dbContext.ApiKeys.Remove(key);
_ = await dbContext.SaveChangesAsync();
return View("Index", new IndexModel { ApiKey = GetUserKeys().ToList() } );
}
public async Task<ActionResult> Details(string id)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
if (key == null)
{
ModelState.AddModelError(null, "Key not found");
return View();
}
return View("Details", new DetailModel { ApiKey = key, Name = key.Name, ProtectedValue = protector.Protect(key.Id)});
}
public async Task<ActionResult> Edit(string id)
{
EditModel edit = new EditModel();
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var user = await _userManager.FindByIdAsync(userId);
edit.ApiKey = await GetUserKeys().SingleOrDefaultAsync(k =>
k.UserId == userId && k.Id == id);
ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
return View(edit);
}
[HttpPost]
public async Task<ActionResult> Edit(EditModel model)
{
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var apiKey = await dbContext.ApiKeys.SingleOrDefaultAsync(k => k.UserId == userId && k.Id == model.ApiKey.Id);
apiKey.Name = model.ApiKey.Name;
apiKey.ValidityPeriodInDays = model.ApiKey.ValidityPeriodInDays;
await dbContext.SaveChangesAsync();
return View("Details", new DetailModel { ApiKey = apiKey });
}
public IQueryable<ApiKey> GetUserKeys()
{
return dbContext.ApiKeys.Include(k => k.User).Where(k => k.User.UserName == User.Identity.Name);
}
}
}

@ -4,6 +4,7 @@ using System.Text;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using nuget_host.Models;
using nuget_host.Models.ApiKeys;
namespace nuget_host.Data
{
@ -13,5 +14,7 @@ namespace nuget_host.Data
: base(options)
{
}
public DbSet<ApiKey> ApiKeys { get; set; }
}
}

@ -4,6 +4,7 @@ namespace nuget_host.Entities
{
public string ProtectionTitle {get; set;}
public string PackagesRootDir {get; set;}
public int MaxUserKeyCount {get; set;}
}
}

@ -0,0 +1,253 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using nuget_host.Data;
namespace nugethost.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20210502153508_api-keys")]
partial class apikeys
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider");
b.Property<string>("ProviderKey");
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider");
b.Property<string>("Name");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("nuget_host.Models.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("nuget_host.Models.ApplicationUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<string>("FullName");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("nuget_host.Models.ApiKey", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace nugethost.Migrations
{
public partial class apikeys : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApiKeys",
columns: table => new
{
Id = table.Column<string>(nullable: false),
UserId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApiKeys", x => x.Id);
table.ForeignKey(
name: "FK_ApiKeys_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ApiKeys_UserId",
table: "ApiKeys",
column: "UserId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApiKeys");
}
}
}

@ -0,0 +1,259 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using nuget_host.Data;
namespace nugethost.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20210508012908_ApkiKey.CreationDate")]
partial class ApkiKeyCreationDate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider");
b.Property<string>("ProviderKey");
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider");
b.Property<string>("Name");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("nuget_host.Models.ApiKeys.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("CreationDate");
b.Property<string>("Name");
b.Property<string>("UserId")
.IsRequired();
b.Property<int>("ValidityPeriodInDays");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("nuget_host.Models.ApplicationUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<string>("FullName");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("nuget_host.Models.ApiKeys.ApiKey", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

@ -0,0 +1,43 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace nugethost.Migrations
{
public partial class ApkiKeyCreationDate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "CreationDate",
table: "ApiKeys",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<string>(
name: "Name",
table: "ApiKeys",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "ValidityPeriodInDays",
table: "ApiKeys",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "CreationDate",
table: "ApiKeys");
migrationBuilder.DropColumn(
name: "Name",
table: "ApiKeys");
migrationBuilder.DropColumn(
name: "ValidityPeriodInDays",
table: "ApiKeys");
}
}
}

@ -126,6 +126,27 @@ namespace nugethost.Migrations
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("nuget_host.Models.ApiKeys.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("CreationDate");
b.Property<string>("Name");
b.Property<string>("UserId")
.IsRequired();
b.Property<int>("ValidityPeriodInDays");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("nuget_host.Models.ApplicationUser", b =>
{
b.Property<string>("Id")
@ -222,6 +243,14 @@ namespace nugethost.Migrations
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("nuget_host.Models.ApiKeys.ApiKey", b =>
{
b.HasOne("nuget_host.Models.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}

@ -0,0 +1,23 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace nuget_host.Models.ApiKeys
{
public class ApiKey
{
[Required][Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
[Required][ForeignKey("User")]
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public string Name { get; set; }
public int ValidityPeriodInDays{ get; set; }
public DateTime CreationDate { get; set; }
}
}

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace nuget_host.Models.ApiKeys
{
public class ApiKeyViewModel
{
[Display(Name = "Key Name")]
public string Name { get; set; }
[Display(Name = "Key Value")]
public string ProtectedValue { get; set; }
}
}

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace nuget_host.Models.ApiKeys
{
public class CreateModel
{
[Required][StringLength(255)]
[Display(Name = "Key Name")]
public string Name { get; set; }
public string UserId { get; set; }
}
}

@ -0,0 +1,7 @@
namespace nuget_host.Models.ApiKeys
{
public class DeleteModel
{
public ApiKey ApiKey { get; set; }
}
}

@ -0,0 +1,8 @@
namespace nuget_host.Models.ApiKeys
{
public class DetailModel : ApiKeyViewModel
{
public ApiKey ApiKey { get; set; }
}
}

@ -0,0 +1,12 @@
namespace nuget_host.Models.ApiKeys
{
public class EditModel
{
public EditModel()
{
if (ApiKey==null) ApiKey = new ApiKey();
}
public ApiKey ApiKey { get; set; }
}
}

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace nuget_host.Models.ApiKeys
{
public class IndexModel
{
public List<ApiKey> ApiKey { get; set; }
}
}

@ -1,27 +0,0 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System;
using System.Collections.Generic;
namespace nuget_host.Models
{
public class GrantsViewModel
{
public IEnumerable<GrantViewModel> Grants { get; set; }
}
public class GrantViewModel
{
public string ClientId { get; set; }
public string ClientName { get; set; }
public string ClientUrl { get; set; }
public string ClientLogoUrl { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public DateTime? Expires { get; set; }
public IEnumerable<string> IdentityGrantNames { get; set; }
public IEnumerable<string> ApiGrantNames { get; set; }
}
}

@ -1,56 +0,0 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace nuget_host.Models
{
public class SecurityHeadersAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
var result = context.Result;
if (result is ViewResult)
{
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Type-Options"))
{
context.HttpContext.Response.Headers.Add("X-Content-Type-Options", "nosniff");
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
if (!context.HttpContext.Response.Headers.ContainsKey("X-Frame-Options"))
{
context.HttpContext.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
var csp = "default-src 'self'; object-src 'none'; frame-ancestors 'none'; sandbox allow-forms allow-same-origin allow-scripts; base-uri 'self';";
// also consider adding upgrade-insecure-requests once you have HTTPS in place for production
//csp += "upgrade-insecure-requests;";
// also an example if you need client images to be displayed from twitter
// csp += "img-src 'self' https://pbs.twimg.com;";
// once for standards compliant browsers
if (!context.HttpContext.Response.Headers.ContainsKey("Content-Security-Policy"))
{
context.HttpContext.Response.Headers.Add("Content-Security-Policy", csp);
}
// and once again for IE
if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Security-Policy"))
{
context.HttpContext.Response.Headers.Add("X-Content-Security-Policy", csp);
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
var referrer_policy = "no-referrer";
if (!context.HttpContext.Response.Headers.ContainsKey("Referrer-Policy"))
{
context.HttpContext.Response.Headers.Add("Referrer-Policy", referrer_policy);
}
}
}
}
}

@ -51,9 +51,9 @@ namespace nuget_host
services.AddTransient<IMailer, EmailSender>();
services.AddTransient<IEmailSender, EmailSender>();
var smtpSettingsconf = Configuration.GetSection("SmtpSettings");
var smtpSettingsconf = Configuration.GetSection("Smtp");
services.Configure<SmtpSettings>(smtpSettingsconf);
var nugetSettingsconf = Configuration.GetSection("NugetSettings");
var nugetSettingsconf = Configuration.GetSection("Nuget");
services.Configure<NugetSettings>(nugetSettingsconf);
}

@ -0,0 +1,35 @@
@model nuget_host.Models.ApiKeys.CreateModel
@{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>ApiKey</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post" asp-controller="ApiKeys">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="UserId" class="control-label"></label>
<select asp-for="UserId" class ="form-control" asp-items="ViewBag.UserId"></select>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>

@ -0,0 +1,46 @@
@model nuget_host.Models.ApiKeys.DeleteModel
@{
ViewData["Title"] = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>ApiKey</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.ApiKey.User)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.User.Id)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ApiKey.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ApiKey.CreationDate)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.CreationDate)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ApiKey.ValidityPeriodInDays)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.ValidityPeriodInDays)
</dd>
</dl>
<form method="post">
<input type="hidden" asp-for="ApiKey.Id" />
<input type="submit" value="Delete" class="btn btn-default" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>

@ -0,0 +1,49 @@
@model nuget_host.Models.ApiKeys.DetailModel
@{
ViewData["Title"] = "Details";
}
<h2>Details</h2>
<div>
<h4>ApiKey</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.ApiKey.User)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.User.Id)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ApiKey.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ApiKey.CreationDate)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.CreationDate)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ApiKey.ValidityPeriodInDays)
</dt>
<dd>
@Html.DisplayFor(model => model.ApiKey.ValidityPeriodInDays)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ProtectedValue)
</dt>
<dd>
@Html.DisplayFor(model => model.ProtectedValue)
</dd>
</dl>
</div>
<div>
<a asp-controller="ApiKeys" asp-action="Edit" asp-route-id="@Model.ApiKey.Id">Edit</a> |
<a asp-controller="ApiKeys" asp-action="Index">Back to List</a>
</div>

@ -0,0 +1,42 @@
@model nuget_host.Models.ApiKeys.EditModel
@{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>ApiKey</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="ApiKey.Id" />
<div class="form-group">
<label asp-for="ApiKey.UserId" class="control-label"></label>
<select asp-for="ApiKey.UserId" class="form-control" asp-items="ViewBag.UserId"></select>
<span asp-validation-for="ApiKey.UserId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ApiKey.Name" class="control-label"></label>
<input asp-for="ApiKey.Name" class="form-control" />
<span asp-validation-for="ApiKey.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ApiKey.ValidityPeriodInDays" class="control-label"></label>
<input asp-for="ApiKey.ValidityPeriodInDays" class="form-control" />
<span asp-validation-for="ApiKey.ValidityPeriodInDays" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>

@ -0,0 +1,54 @@
@model nuget_host.Models.ApiKeys.IndexModel
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-controller="ApiKeys" asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.ApiKey[0].User)
</th>
<th>
@Html.DisplayNameFor(model => model.ApiKey[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.ApiKey[0].CreationDate)
</th>
<th>
@Html.DisplayNameFor(model => model.ApiKey[0].ValidityPeriodInDays)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.ApiKey) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.User.Id)
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.CreationDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.ValidityPeriodInDays)
</td>
<td>
<a asp-controller="ApiKeys" asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-controller="ApiKeys" asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-controller="ApiKeys" asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>

@ -1,87 +0,0 @@
@model GrantsViewModel
<div class="grants-page">
<div class="lead">
<h1>Client Application Permissions</h1>
<p>Below is the list of applications you have given permission to and the resources they have access to.</p>
</div>
@if (Model.Grants.Any() == false)
{
<div class="row">
<div class="col-sm-8">
<div class="alert alert-info">
You have not given access to any applications
</div>
</div>
</div>
}
else
{
foreach (var grant in Model.Grants)
{
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-sm-8 card-title">
@if (grant.ClientLogoUrl != null)
{
<img src="@grant.ClientLogoUrl">
}
<strong>@grant.ClientName</strong>
</div>
<div class="col-sm-2">
<form asp-action="Revoke">
<input type="hidden" name="clientId" value="@grant.ClientId">
<button class="btn btn-danger">Revoke Access</button>
</form>
</div>
</div>
</div>
<ul class="list-group list-group-flush">
@if (grant.Description != null)
{
<li class="list-group-item">
<label>Description:</label> @grant.Description
</li>
}
<li class="list-group-item">
<label>Created:</label> @grant.Created.ToString("yyyy-MM-dd")
</li>
@if (grant.Expires.HasValue)
{
<li class="list-group-item">
<label>Expires:</label> @grant.Expires.Value.ToString("yyyy-MM-dd")
</li>
}
@if (grant.IdentityGrantNames.Any())
{
<li class="list-group-item">
<label>Identity Grants</label>
<ul>
@foreach (var name in grant.IdentityGrantNames)
{
<li>@name</li>
}
</ul>
</li>
}
@if (grant.ApiGrantNames.Any())
{
<li class="list-group-item">
<label>API Grants</label>
<ul>
@foreach (var name in grant.ApiGrantNames)
{
<li>@name</li>
}
</ul>
</li>
}
</ul>
</div>
}
}
</div>

@ -1,5 +1,6 @@
@{
ViewData["Title"] = "Home Page";}
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>

@ -1,7 +1,8 @@
{
"NuGet": {
"Nuget": {
"ExternalUrl" : "<http://localhost:5000/packages",
"PackagesRootDir" : "packages"
"PackagesRootDir" : "packages",
"MaxUserKeyCount": 5
},
"Smtp": {
"Server": "localhost",

@ -1,9 +1,10 @@
{
"RootApiKeySecret": "<your-root-api-clear-key>",
"NuGet": {
"Nuget": {
"ExternalUrl" : "<http://your-external.url",
"PackagesRootDir" : "<your-Source-dir>",
"ProtectionTitle": "protected-data-v1"
"ProtectionTitle": "protected-data-v1",
"MaxUserKeyCount": 1
},
"ConnectionStrings": {
"DefaultConnection": "Server=<pqserver>;Port=<pqport>;Database=<dbname>;Username=<dbusername>;Password=<dbpass>;"

Loading…