diff --git a/src/Ombi.Core/Ombi.Core.csproj b/src/Ombi.Core/Ombi.Core.csproj
index 2f2e35861..38caf6f3d 100644
--- a/src/Ombi.Core/Ombi.Core.csproj
+++ b/src/Ombi.Core/Ombi.Core.csproj
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj
index efbf3dade..fe4befec3 100644
--- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj
+++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/src/Ombi.Mapping/Profiles/OmbiProfile.cs b/src/Ombi.Mapping/Profiles/OmbiProfile.cs
index 8b6d4f058..8bd03121e 100644
--- a/src/Ombi.Mapping/Profiles/OmbiProfile.cs
+++ b/src/Ombi.Mapping/Profiles/OmbiProfile.cs
@@ -18,7 +18,7 @@ namespace Ombi.Mapping.Profiles
CreateMap().ConvertUsing();
- CreateMap().ForMember(x => x.Password, opt => opt.Ignore());
+ CreateMap().ForMember(x => x.Password, opt => opt.Ignore());
CreateMap()
.ConstructUsing(checkbox => checkbox.Enabled ? new Claim(ClaimTypes.Role, checkbox.Value) : new Claim(ClaimTypes.Country, ""));
diff --git a/src/Ombi.Store/Context/IOmbiContext.cs b/src/Ombi.Store/Context/IOmbiContext.cs
index 7bd8279b1..4d71fcaa3 100644
--- a/src/Ombi.Store/Context/IOmbiContext.cs
+++ b/src/Ombi.Store/Context/IOmbiContext.cs
@@ -17,7 +17,7 @@ namespace Ombi.Store.Context
DbSet PlexContent { get; set; }
DbSet RadarrCache { get; set; }
DatabaseFacade Database { get; }
- DbSet Users { get; set; }
+ DbSet OldUsers { get; set; }
EntityEntry Entry(T entry) where T : class;
EntityEntry Attach(TEntity entity) where TEntity : class;
DbSet Set() where TEntity : class;
diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs
index 8d9902290..491732f80 100644
--- a/src/Ombi.Store/Context/OmbiContext.cs
+++ b/src/Ombi.Store/Context/OmbiContext.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Ombi.Helpers;
using Ombi.Store.Entities;
@@ -7,7 +8,7 @@ using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Context
{
- public sealed class OmbiContext : DbContext, IOmbiContext
+ public sealed class OmbiContext : IdentityDbContext, IOmbiContext
{
private static bool _created;
public OmbiContext()
@@ -19,10 +20,12 @@ namespace Ombi.Store.Context
// Add the notifcation templates
AddAllTemplates();
+
}
-
+
+
public DbSet Settings { get; set; }
- public DbSet Users { get; set; }
+ public DbSet OldUsers { get; set; }
public DbSet PlexContent { get; set; }
public DbSet RadarrCache { get; set; }
public DbSet NotificationTemplates { get; set; }
diff --git a/src/Ombi.Store/Entities/OmbiUser.cs b/src/Ombi.Store/Entities/OmbiUser.cs
new file mode 100644
index 000000000..377e47247
--- /dev/null
+++ b/src/Ombi.Store/Entities/OmbiUser.cs
@@ -0,0 +1,14 @@
+using System.ComponentModel.DataAnnotations.Schema;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
+
+namespace Ombi.Store.Entities
+{
+ public class OmbiUser : IdentityUser
+ {
+ public string Alias { get; set; }
+ public UserType UserType { get; set; }
+
+ [NotMapped]
+ public string UserAlias => string.IsNullOrEmpty(Alias) ? UserName : Alias;
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Store/Migrations/20170703134019_Initial.Designer.cs b/src/Ombi.Store/Migrations/20170712080109_Initial.Designer.cs
similarity index 60%
rename from src/Ombi.Store/Migrations/20170703134019_Initial.Designer.cs
rename to src/Ombi.Store/Migrations/20170712080109_Initial.Designer.cs
index 78e6f1172..020a66fdb 100644
--- a/src/Ombi.Store/Migrations/20170703134019_Initial.Designer.cs
+++ b/src/Ombi.Store/Migrations/20170712080109_Initial.Designer.cs
@@ -10,13 +10,142 @@ using Ombi.Store.Entities;
namespace Ombi.Store.Migrations
{
[DbContext(typeof(OmbiContext))]
- [Migration("20170703134019_Initial")]
+ [Migration("20170712080109_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
modelBuilder
- .HasAnnotation("ProductVersion", "1.1.1");
+ .HasAnnotation("ProductVersion", "1.1.2");
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Name")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("RoleId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider");
+
+ b.Property("ProviderKey");
+
+ b.Property("ProviderDisplayName");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("RoleId");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider");
+
+ b.Property("Name");
+
+ b.Property("Value");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens");
+ });
+
+ modelBuilder.Entity("Ombi.Store.Entities.EmailTokens", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DateUsed");
+
+ b.Property("Token");
+
+ b.Property("Used");
+
+ b.Property("UserId");
+
+ b.Property("ValidUntil");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("EmailTokens");
+ });
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
{
@@ -52,6 +181,60 @@ namespace Ombi.Store.Migrations
b.ToTable("NotificationTemplates");
});
+ modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount");
+
+ b.Property("Alias");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed");
+
+ b.Property("LockoutEnabled");
+
+ b.Property("LockoutEnd");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash");
+
+ b.Property("PhoneNumber");
+
+ b.Property("PhoneNumberConfirmed");
+
+ b.Property("SecurityStamp");
+
+ b.Property("TwoFactorEnabled");
+
+ b.Property("UserName")
+ .HasMaxLength(256);
+
+ b.Property("UserType");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasName("UserNameIndex");
+
+ b.ToTable("AspNetUsers");
+ });
+
modelBuilder.Entity("Ombi.Store.Entities.PlexContent", b =>
{
b.Property("Id")
@@ -131,6 +314,8 @@ namespace Ombi.Store.Migrations
b.Property("RequestedUserId");
+ b.Property("Title");
+
b.HasKey("Id");
b.HasIndex("ParentRequestId");
@@ -273,7 +458,7 @@ namespace Ombi.Store.Migrations
b.HasKey("Id");
- b.ToTable("Users");
+ b.ToTable("OldUsers");
});
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
@@ -320,6 +505,51 @@ namespace Ombi.Store.Migrations
b.ToTable("SeasonRequests");
});
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+ .WithMany("Claims")
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
+ {
+ b.HasOne("Ombi.Store.Entities.OmbiUser")
+ .WithMany("Claims")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
+ {
+ b.HasOne("Ombi.Store.Entities.OmbiUser")
+ .WithMany("Logins")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+ .WithMany("Users")
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("Ombi.Store.Entities.OmbiUser")
+ .WithMany("Roles")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Ombi.Store.Entities.EmailTokens", b =>
+ {
+ b.HasOne("Ombi.Store.Entities.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexContent")
diff --git a/src/Ombi.Store/Migrations/20170703134019_Initial.cs b/src/Ombi.Store/Migrations/20170712080109_Initial.cs
similarity index 62%
rename from src/Ombi.Store/Migrations/20170703134019_Initial.cs
rename to src/Ombi.Store/Migrations/20170712080109_Initial.cs
index edca99333..907e42e21 100644
--- a/src/Ombi.Store/Migrations/20170703134019_Initial.cs
+++ b/src/Ombi.Store/Migrations/20170712080109_Initial.cs
@@ -8,6 +8,34 @@ namespace Ombi.Store.Migrations
{
protected override void Up(MigrationBuilder migrationBuilder)
{
+ migrationBuilder.CreateTable(
+ name: "AspNetRoles",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ ConcurrencyStamp = table.Column(nullable: true),
+ Name = table.Column(maxLength: 256, nullable: true),
+ NormalizedName = table.Column(maxLength: 256, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetRoles", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserTokens",
+ columns: table => new
+ {
+ UserId = table.Column(nullable: false),
+ LoginProvider = table.Column(nullable: false),
+ Name = table.Column(nullable: false),
+ Value = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
+ });
+
migrationBuilder.CreateTable(
name: "GlobalSettings",
columns: table => new
@@ -39,6 +67,33 @@ namespace Ombi.Store.Migrations
table.PrimaryKey("PK_NotificationTemplates", x => x.Id);
});
+ migrationBuilder.CreateTable(
+ name: "AspNetUsers",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ AccessFailedCount = table.Column(nullable: false),
+ Alias = table.Column(nullable: true),
+ ConcurrencyStamp = table.Column(nullable: true),
+ Email = table.Column(maxLength: 256, nullable: true),
+ EmailConfirmed = table.Column(nullable: false),
+ LockoutEnabled = table.Column(nullable: false),
+ LockoutEnd = table.Column(nullable: true),
+ NormalizedEmail = table.Column(maxLength: 256, nullable: true),
+ NormalizedUserName = table.Column(maxLength: 256, nullable: true),
+ PasswordHash = table.Column(nullable: true),
+ PhoneNumber = table.Column(nullable: true),
+ PhoneNumberConfirmed = table.Column(nullable: false),
+ SecurityStamp = table.Column(nullable: true),
+ TwoFactorEnabled = table.Column(nullable: false),
+ UserName = table.Column(maxLength: 256, nullable: true),
+ UserType = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUsers", x => x.Id);
+ });
+
migrationBuilder.CreateTable(
name: "PlexContent",
columns: table => new
@@ -92,7 +147,7 @@ namespace Ombi.Store.Migrations
});
migrationBuilder.CreateTable(
- name: "Users",
+ name: "OldUsers",
columns: table => new
{
Id = table.Column(nullable: false)
@@ -107,7 +162,93 @@ namespace Ombi.Store.Migrations
},
constraints: table =>
{
- table.PrimaryKey("PK_Users", x => x.Id);
+ table.PrimaryKey("PK_OldUsers", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetRoleClaims",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ ClaimType = table.Column(nullable: true),
+ ClaimValue = table.Column(nullable: true),
+ RoleId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
+ table.ForeignKey(
+ name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
+ column: x => x.RoleId,
+ principalTable: "AspNetRoles",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserClaims",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ ClaimType = table.Column(nullable: true),
+ ClaimValue = table.Column(nullable: true),
+ UserId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
+ table.ForeignKey(
+ name: "FK_AspNetUserClaims_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserLogins",
+ columns: table => new
+ {
+ LoginProvider = table.Column(nullable: false),
+ ProviderKey = table.Column(nullable: false),
+ ProviderDisplayName = table.Column(nullable: true),
+ UserId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
+ table.ForeignKey(
+ name: "FK_AspNetUserLogins_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserRoles",
+ columns: table => new
+ {
+ UserId = table.Column(nullable: false),
+ RoleId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
+ table.ForeignKey(
+ name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
+ column: x => x.RoleId,
+ principalTable: "AspNetRoles",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_AspNetUserRoles_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
@@ -132,6 +273,29 @@ namespace Ombi.Store.Migrations
onDelete: ReferentialAction.Cascade);
});
+ migrationBuilder.CreateTable(
+ name: "EmailTokens",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ DateUsed = table.Column(nullable: false),
+ Token = table.Column(nullable: false),
+ Used = table.Column(nullable: false),
+ UserId = table.Column(nullable: false),
+ ValidUntil = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_EmailTokens", x => x.Id);
+ table.ForeignKey(
+ name: "FK_EmailTokens_OldUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "OldUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
migrationBuilder.CreateTable(
name: "ChildRequests",
columns: table => new
@@ -159,9 +323,9 @@ namespace Ombi.Store.Migrations
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
- name: "FK_ChildRequests_Users_RequestedUserId",
+ name: "FK_ChildRequests_OldUsers_RequestedUserId",
column: x => x.RequestedUserId,
- principalTable: "Users",
+ principalTable: "OldUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
@@ -192,9 +356,9 @@ namespace Ombi.Store.Migrations
{
table.PrimaryKey("PK_MovieRequests", x => x.Id);
table.ForeignKey(
- name: "FK_MovieRequests_Users_RequestedUserId",
+ name: "FK_MovieRequests_OldUsers_RequestedUserId",
column: x => x.RequestedUserId,
- principalTable: "Users",
+ principalTable: "OldUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
@@ -301,6 +465,48 @@ namespace Ombi.Store.Migrations
onDelete: ReferentialAction.Cascade);
});
+ migrationBuilder.CreateIndex(
+ name: "RoleNameIndex",
+ table: "AspNetRoles",
+ column: "NormalizedName",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetRoleClaims_RoleId",
+ table: "AspNetRoleClaims",
+ column: "RoleId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetUserClaims_UserId",
+ table: "AspNetUserClaims",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetUserLogins_UserId",
+ table: "AspNetUserLogins",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetUserRoles_RoleId",
+ table: "AspNetUserRoles",
+ column: "RoleId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_EmailTokens_UserId",
+ table: "EmailTokens",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "EmailIndex",
+ table: "AspNetUsers",
+ column: "NormalizedEmail");
+
+ migrationBuilder.CreateIndex(
+ name: "UserNameIndex",
+ table: "AspNetUsers",
+ column: "NormalizedUserName",
+ unique: true);
+
migrationBuilder.CreateIndex(
name: "IX_PlexSeasonsContent_PlexContentId",
table: "PlexSeasonsContent",
@@ -354,6 +560,24 @@ namespace Ombi.Store.Migrations
protected override void Down(MigrationBuilder migrationBuilder)
{
+ migrationBuilder.DropTable(
+ name: "AspNetRoleClaims");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserClaims");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserLogins");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserRoles");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserTokens");
+
+ migrationBuilder.DropTable(
+ name: "EmailTokens");
+
migrationBuilder.DropTable(
name: "GlobalSettings");
@@ -375,6 +599,12 @@ namespace Ombi.Store.Migrations
migrationBuilder.DropTable(
name: "EpisodeRequests");
+ migrationBuilder.DropTable(
+ name: "AspNetRoles");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUsers");
+
migrationBuilder.DropTable(
name: "PlexContent");
@@ -391,7 +621,7 @@ namespace Ombi.Store.Migrations
name: "TvRequests");
migrationBuilder.DropTable(
- name: "Users");
+ name: "OldUsers");
}
}
}
diff --git a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs
index 7b7237f35..0a5397d0b 100644
--- a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs
+++ b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs
@@ -15,7 +15,136 @@ namespace Ombi.Store.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
modelBuilder
- .HasAnnotation("ProductVersion", "1.1.1");
+ .HasAnnotation("ProductVersion", "1.1.2");
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Name")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("RoleId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider");
+
+ b.Property("ProviderKey");
+
+ b.Property("ProviderDisplayName");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("RoleId");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider");
+
+ b.Property("Name");
+
+ b.Property("Value");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens");
+ });
+
+ modelBuilder.Entity("Ombi.Store.Entities.EmailTokens", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DateUsed");
+
+ b.Property("Token");
+
+ b.Property("Used");
+
+ b.Property("UserId");
+
+ b.Property("ValidUntil");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("EmailTokens");
+ });
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
{
@@ -51,6 +180,60 @@ namespace Ombi.Store.Migrations
b.ToTable("NotificationTemplates");
});
+ modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount");
+
+ b.Property("Alias");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed");
+
+ b.Property("LockoutEnabled");
+
+ b.Property("LockoutEnd");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash");
+
+ b.Property("PhoneNumber");
+
+ b.Property("PhoneNumberConfirmed");
+
+ b.Property("SecurityStamp");
+
+ b.Property("TwoFactorEnabled");
+
+ b.Property("UserName")
+ .HasMaxLength(256);
+
+ b.Property("UserType");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasName("UserNameIndex");
+
+ b.ToTable("AspNetUsers");
+ });
+
modelBuilder.Entity("Ombi.Store.Entities.PlexContent", b =>
{
b.Property("Id")
@@ -130,6 +313,8 @@ namespace Ombi.Store.Migrations
b.Property("RequestedUserId");
+ b.Property("Title");
+
b.HasKey("Id");
b.HasIndex("ParentRequestId");
@@ -272,7 +457,7 @@ namespace Ombi.Store.Migrations
b.HasKey("Id");
- b.ToTable("Users");
+ b.ToTable("OldUsers");
});
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
@@ -319,6 +504,51 @@ namespace Ombi.Store.Migrations
b.ToTable("SeasonRequests");
});
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+ .WithMany("Claims")
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b =>
+ {
+ b.HasOne("Ombi.Store.Entities.OmbiUser")
+ .WithMany("Claims")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b =>
+ {
+ b.HasOne("Ombi.Store.Entities.OmbiUser")
+ .WithMany("Logins")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+ .WithMany("Users")
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("Ombi.Store.Entities.OmbiUser")
+ .WithMany("Roles")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Ombi.Store.Entities.EmailTokens", b =>
+ {
+ b.HasOne("Ombi.Store.Entities.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexContent")
diff --git a/src/Ombi.Store/Ombi.Store.csproj b/src/Ombi.Store/Ombi.Store.csproj
index 4ebe158cc..c68a68d20 100644
--- a/src/Ombi.Store/Ombi.Store.csproj
+++ b/src/Ombi.Store/Ombi.Store.csproj
@@ -5,10 +5,11 @@
-
-
-
-
+
+
+
+
+
diff --git a/src/Ombi.Store/Repository/UserRepository.cs b/src/Ombi.Store/Repository/UserRepository.cs
index df1ea5574..38f49edc7 100644
--- a/src/Ombi.Store/Repository/UserRepository.cs
+++ b/src/Ombi.Store/Repository/UserRepository.cs
@@ -45,32 +45,32 @@ namespace Ombi.Store.Repository
public async Task GetUser(string username)
{
- var user = await Db.Users.FirstOrDefaultAsync(x => x.Username.ToLower() == username.ToLower());
+ var user = await Db.OldUsers.FirstOrDefaultAsync(x => x.Username.ToLower() == username.ToLower());
Db.Entry(user).Reload();
return user;
}
public async Task GetUser(int userId)
{
- var user = await Db.Users.FirstOrDefaultAsync(x => x.Id == userId);
+ var user = await Db.OldUsers.FirstOrDefaultAsync(x => x.Id == userId);
Db.Entry(user).Reload();
return user;
}
public async Task CreateUser(User user)
{
- Db.Users.Add(user);
+ Db.OldUsers.Add(user);
await Db.SaveChangesAsync();
}
public async Task> GetUsers()
{
- return await Db.Users.ToListAsync();
+ return await Db.OldUsers.ToListAsync();
}
public async Task DeleteUser(User user)
{
- Db.Users.Remove(user);
+ Db.OldUsers.Remove(user);
await Db.SaveChangesAsync();
}
diff --git a/src/Ombi/Auth/CustomJwtDataFormat.cs b/src/Ombi/Auth/CustomJwtDataFormat.cs
deleted file mode 100644
index de8eccaae..000000000
--- a/src/Ombi/Auth/CustomJwtDataFormat.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System;
-using System.IdentityModel.Tokens.Jwt;
-using System.Security.Claims;
-using Microsoft.AspNetCore.Authentication;
-using Microsoft.AspNetCore.Http.Authentication;
-using Microsoft.IdentityModel.Tokens;
-
-namespace Ombi.Auth
-{
- public class CustomJwtDataFormat : ISecureDataFormat
- {
- private readonly string algorithm;
- private readonly TokenValidationParameters validationParameters;
-
- public CustomJwtDataFormat(string algorithm, TokenValidationParameters validationParameters)
- {
- this.algorithm = algorithm;
- this.validationParameters = validationParameters;
- }
-
- public AuthenticationTicket Unprotect(string protectedText)
- => Unprotect(protectedText, null);
-
- public AuthenticationTicket Unprotect(string protectedText, string purpose)
- {
- var handler = new JwtSecurityTokenHandler();
- ClaimsPrincipal principal = null;
- SecurityToken validToken = null;
-
- try
- {
- principal = handler.ValidateToken(protectedText, this.validationParameters, out validToken);
-
- var validJwt = validToken as JwtSecurityToken;
-
- if (validJwt == null)
- {
- throw new ArgumentException("Invalid JWT");
- }
-
- if (!validJwt.Header.Alg.Equals(algorithm, StringComparison.Ordinal))
- {
- throw new ArgumentException($"Algorithm must be '{algorithm}'");
- }
-
- // Additional custom validation of JWT claims here (if any)
- }
- catch (SecurityTokenValidationException)
- {
- return null;
- }
- catch (ArgumentException)
- {
- return null;
- }
-
- // Validation passed. Return a valid AuthenticationTicket:
- return new AuthenticationTicket(principal, new AuthenticationProperties(), "Cookie");
- }
-
- // This ISecureDataFormat implementation is decode-only
- public string Protect(AuthenticationTicket data)
- {
- throw new NotImplementedException();
- }
-
- public string Protect(AuthenticationTicket data, string purpose)
- {
- throw new NotImplementedException();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Ombi/Auth/TokenAuthenticationOptions.cs b/src/Ombi/Auth/TokenAuthenticationOptions.cs
deleted file mode 100644
index 657872e80..000000000
--- a/src/Ombi/Auth/TokenAuthenticationOptions.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Ombi.Auth
-{
- public class TokenAuthenticationOptions
- {
- public string SecretKey { get; set; }
- public string Issuer { get; set; }
- public string Audience { get; set; }
- public string TokenPath { get; set; }
- public string CookieName { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Ombi/Auth/TokenProviderMiddleware.cs b/src/Ombi/Auth/TokenProviderMiddleware.cs
deleted file mode 100644
index f928b6049..000000000
--- a/src/Ombi/Auth/TokenProviderMiddleware.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IdentityModel.Tokens.Jwt;
-using System.IO;
-using System.Linq;
-using System.Security.Claims;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Options;
-using Newtonsoft.Json;
-using Ombi.Core.IdentityResolver;
-using Ombi.Models;
-using Ombi.Store.Context;
-using Ombi.Store.Repository;
-
-namespace Ombi.Auth
-{
- public class TokenProviderMiddleware
- {
- private readonly RequestDelegate _next;
- private readonly TokenProviderOptions _options;
- private readonly JsonSerializerSettings _serializerSettings;
- private readonly IUserIdentityManager _identityManager;
-
- public TokenProviderMiddleware(
- RequestDelegate next,
- IOptions options, IUserIdentityManager manager)
- {
- _next = next;
- _options = options.Value;
- ThrowIfInvalidOptions(_options);
-
- _serializerSettings = new JsonSerializerSettings
- {
- Formatting = Formatting.Indented
- };
- _identityManager = manager;
- }
-
- public Task Invoke(HttpContext context)
- {
- // If the request path doesn't match, skip
- if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal))
- {
- try
- {
-
- return _next(context);
- }
- catch (Exception e)
- {
-
- throw;
- }
- }
-
- // Request must be POST with Content-Type: application/json
- if (!context.Request.Method.Equals("POST")
- )
- {
- context.Response.StatusCode = 400;
- return context.Response.WriteAsync("Bad request.");
- }
-
-
- return GenerateToken(context);
- }
-
- private async Task GenerateToken(HttpContext context)
- {
- var request = context.Request;
- UserAuthModel userInfo;
-
- using (var bodyReader = new StreamReader(request.Body))
- {
- string body = await bodyReader.ReadToEndAsync();
- userInfo = JsonConvert.DeserializeObject(body);
- }
-
- var identity = await _options.IdentityResolver(userInfo.Username, userInfo.Password, _identityManager);
- if (identity == null)
- {
- context.Response.StatusCode = 400;
- await context.Response.WriteAsync("Invalid username or password.");
- return;
- }
-
- var now = DateTime.UtcNow;
-
- // Specifically add the jti (nonce), iat (issued timestamp), and sub (subject/user) claims.
- // You can add other claims here, if you want:
- var jwtClaims = new List
- {
- new Claim(JwtRegisteredClaimNames.Sub, userInfo.Username),
- new Claim(JwtRegisteredClaimNames.Jti, await _options.NonceGenerator()),
- new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(now).ToUniversalTime().ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
- };
-
- identity.Claims.ToList().AddRange(jwtClaims);
-
- // Create the JWT and write it to a string
- var jwt = new JwtSecurityToken(
- issuer: _options.Issuer,
- audience: _options.Audience,
- claims: identity.Claims,
- notBefore: now,
- expires: now.Add(_options.Expiration),
- signingCredentials: _options.SigningCredentials);
- var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
-
- var response = new
- {
- access_token = encodedJwt,
- expires_in = (int)_options.Expiration.TotalSeconds
- };
-
- // Serialize and return the response
- context.Response.ContentType = "application/json";
- await context.Response.WriteAsync(JsonConvert.SerializeObject(response, _serializerSettings));
- }
-
- private static void ThrowIfInvalidOptions(TokenProviderOptions options)
- {
- if (string.IsNullOrEmpty(options.Path))
- {
- throw new ArgumentNullException(nameof(TokenProviderOptions.Path));
- }
-
- if (string.IsNullOrEmpty(options.Issuer))
- {
- throw new ArgumentNullException(nameof(TokenProviderOptions.Issuer));
- }
-
- if (string.IsNullOrEmpty(options.Audience))
- {
- throw new ArgumentNullException(nameof(TokenProviderOptions.Audience));
- }
-
- if (options.Expiration == TimeSpan.Zero)
- {
- throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(TokenProviderOptions.Expiration));
- }
-
- if (options.IdentityResolver == null)
- {
- throw new ArgumentNullException(nameof(TokenProviderOptions.IdentityResolver));
- }
-
- if (options.SigningCredentials == null)
- {
- throw new ArgumentNullException(nameof(TokenProviderOptions.SigningCredentials));
- }
-
- if (options.NonceGenerator == null)
- {
- throw new ArgumentNullException(nameof(TokenProviderOptions.NonceGenerator));
- }
- }
-
- }
-}
\ No newline at end of file
diff --git a/src/Ombi/Auth/TokenProviderOptions.cs b/src/Ombi/Auth/TokenProviderOptions.cs
deleted file mode 100644
index d48b23392..000000000
--- a/src/Ombi/Auth/TokenProviderOptions.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Security.Claims;
-using System.Security.Cryptography;
-using System.Threading.Tasks;
-using Microsoft.IdentityModel.Tokens;
-using Ombi.Core.IdentityResolver;
-
-namespace Ombi.Auth
-{
- public class TokenProviderOptions
- {
- ///
- /// The relative request path to listen on.
- ///
- /// The default path is /token.
- public string Path { get; set; } = "/token/";
-
- ///
- /// The Issuer (iss) claim for generated tokens.
- ///
- public string Issuer { get; set; }
-
- ///
- /// The Audience (aud) claim for the generated tokens.
- ///
- public string Audience { get; set; }
-
- ///
- /// The expiration time for the generated tokens.
- ///
- /// The default is 1 Days.
- public TimeSpan Expiration { get; set; } = TimeSpan.FromDays(1);
-
- ///
- /// The signing key to use when generating tokens.
- ///
- public SigningCredentials SigningCredentials { get; set; }
-
- ///
- /// Resolves a user identity given a username and password.
- ///
- public Func> IdentityResolver { get; set; }
-
- ///
- /// Generates a random value (nonce) for each generated token.
- ///
- /// The default nonce is a random GUID.
- public Func> NonceGenerator { get; set; }
- = () => Task.FromResult(Guid.NewGuid().ToString());
- }
-}
diff --git a/src/Ombi/ClientApp/app/auth/auth.service.ts b/src/Ombi/ClientApp/app/auth/auth.service.ts
index 645e74cf4..0f81ca289 100644
--- a/src/Ombi/ClientApp/app/auth/auth.service.ts
+++ b/src/Ombi/ClientApp/app/auth/auth.service.ts
@@ -1,5 +1,4 @@
-
-import { Injectable } from '@angular/core';
+import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { ServiceHelpers } from '../services/service.helpers';
@@ -8,18 +7,28 @@ import { IUserLogin, ILocalUser } from './IUserLogin';
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';
-import { Http } from '@angular/http';
+import { Http, Headers, URLSearchParams } from '@angular/http';
@Injectable()
export class AuthService extends ServiceHelpers {
constructor(http: Http) {
- super(http, '/api/v1/token');
+ super(http, '/connect/token');
}
jwtHelper: JwtHelper = new JwtHelper();
- login(login:IUserLogin) : Observable {
- return this.http.post(`${this.url}/`, JSON.stringify(login), { headers: this.headers })
+ login(login: IUserLogin): Observable {
+ this.headers = new Headers();
+ this.headers.append('Content-Type', 'application/x-www-form-urlencoded');
+ let data = new URLSearchParams();
+ data.append('client_id', 'frontend');
+ data.append('scope', 'api');
+ data.append('client_secret', 'secret');
+ data.append('grant_type', 'password');
+ data.append('username', login.username);
+ data.append('password', login.password);
+
+ return this.http.post(`${this.url}/`, data.toString(), { headers: this.headers })
.map(this.extractData);
}
diff --git a/src/Ombi/ClientApp/app/requests/tvrequest-manage.component.html b/src/Ombi/ClientApp/app/requests/tvrequest-manage.component.html
index 73b4be136..ba8049ff9 100644
--- a/src/Ombi/ClientApp/app/requests/tvrequest-manage.component.html
+++ b/src/Ombi/ClientApp/app/requests/tvrequest-manage.component.html
@@ -1,9 +1,7 @@
\ No newline at end of file
diff --git a/src/Ombi/Config/UserSettings.cs b/src/Ombi/Config/UserSettings.cs
new file mode 100644
index 000000000..49ccadb95
--- /dev/null
+++ b/src/Ombi/Config/UserSettings.cs
@@ -0,0 +1,8 @@
+namespace Ombi.Config
+{
+ public class UserSettings
+ {
+ public string WebsiteUrl { get; set; }
+ public bool UseHttps { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi/Controllers/IdentityController.cs b/src/Ombi/Controllers/IdentityController.cs
index 9ca9319d7..3e3d4302d 100644
--- a/src/Ombi/Controllers/IdentityController.cs
+++ b/src/Ombi/Controllers/IdentityController.cs
@@ -1,18 +1,18 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-using System.Security.Claims;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
using Ombi.Attributes;
using Ombi.Core.Claims;
-using Ombi.Core.IdentityResolver;
-using Ombi.Core.Models;
using Ombi.Core.Models.UI;
using Ombi.Models;
+using Ombi.Store.Entities;
namespace Ombi.Controllers
{
@@ -23,13 +23,15 @@ namespace Ombi.Controllers
[PowerUser]
public class IdentityController : BaseV1ApiController
{
- public IdentityController(IUserIdentityManager identity, IMapper mapper)
+ public IdentityController(UserManager user, IMapper mapper, RoleManager rm)
{
- IdentityManager = identity;
+ UserManager = user;
Mapper = mapper;
+ RoleManager = rm;
}
- private IUserIdentityManager IdentityManager { get; }
+ private UserManager UserManager { get; }
+ private RoleManager RoleManager { get; }
private IMapper Mapper { get; }
///
@@ -39,10 +41,9 @@ namespace Ombi.Controllers
[HttpGet]
public async Task GetUser()
{
- return Mapper.Map(await IdentityManager.GetUser(this.HttpContext.User.Identity.Name));
+ return Mapper.Map(await UserManager.GetUserAsync(User));
}
-
///
/// This is what the Wizard will call when creating the user for the very first time.
/// This should never be called after this.
@@ -57,20 +58,39 @@ namespace Ombi.Controllers
[AllowAnonymous]
public async Task CreateWizardUser([FromBody] UserAuthModel user)
{
- var users = await IdentityManager.GetUsers();
+ var users = UserManager.Users;
if (users.Any())
{
// No one should be calling this. Only the wizard
return false;
}
- await IdentityManager.CreateUser(new UserDto
+ var userToCreate = new OmbiUser
+ {
+ UserName = user.Username,
+
+ };
+
+ var result = await UserManager.CreateAsync(userToCreate, user.Password);
+ if (result.Succeeded)
{
- Username = user.Username,
- UserType = UserType.LocalUser,
- Claims = new List() { new Claim(ClaimTypes.Role, OmbiClaims.Admin) },
- Password = user.Password,
- });
+ if (!(await RoleManager.RoleExistsAsync("Admin")))
+ {
+ var r = await RoleManager.CreateAsync(new IdentityRole("Admin"));
+ }
+ var re = await UserManager.AddToRoleAsync(userToCreate, "Admin");
+
+ var v = User.IsInRole("Admin");
+
+
+ }
+ //await UserManager.CreateUser(new UserDto
+ //{
+ // Username = user.Username,
+ // UserType = UserType.LocalUser,
+ // Claims = new List() { new Claim(ClaimTypes.Role, OmbiClaims.Admin) },
+ // Password = user.Password,
+ //});
return true;
}
@@ -88,7 +108,7 @@ namespace Ombi.Controllers
var fields = fieldInfos.Where(fi => fi.IsLiteral && !fi.IsInitOnly).ToList();
var allClaims = fields.Select(x => x.Name).ToList();
- var users = Mapper.Map>(await IdentityManager.GetUsers()).ToList();
+ var users = Mapper.Map>(UserManager.Users).ToList();
foreach (var user in users)
{
@@ -121,7 +141,7 @@ namespace Ombi.Controllers
var fields = fieldInfos.Where(fi => fi.IsLiteral && !fi.IsInitOnly).ToList();
var allClaims = fields.Select(x => x.Name).ToList();
- var user = Mapper.Map(await IdentityManager.GetUser(id));
+ var user = Mapper.Map(await UserManager.Users.FirstOrDefaultAsync(x => x.Id == id.ToString()));
var userClaims = user.Claims.Select(x => x.Value);
@@ -145,37 +165,37 @@ namespace Ombi.Controllers
///
/// The user.
///
- [HttpPost]
- public async Task CreateUser([FromBody] UserViewModel user)
- {
- user.Id = null;
- var userResult = await IdentityManager.CreateUser(Mapper.Map(user));
- return Mapper.Map(userResult);
- }
-
- ///
- /// Updates the user.
- ///
- /// The user.
- ///
- [HttpPut]
- public async Task UpdateUser([FromBody] UserViewModel user)
- {
- var userResult = await IdentityManager.UpdateUser(Mapper.Map(user));
- return Mapper.Map(userResult);
- }
+ //[HttpPost]
+ //public async Task CreateUser([FromBody] UserViewModel user)
+ //{
+ // user.Id = null;
+ // var userResult = await UserManager.CreateUser(Mapper.Map(user));
+ // return Mapper.Map(userResult);
+ //}
///
- /// Deletes the user.
+ /// Updates the user.
///
/// The user.
///
- [HttpDelete]
- public async Task DeleteUser([FromBody] UserViewModel user)
- {
- await IdentityManager.DeleteUser(Mapper.Map(user));
- return Ok();
- }
+ //[HttpPut]
+ //public async Task UpdateUser([FromBody] UserViewModel user)
+ //{
+ // var userResult = await UserManager.UpdateUser(Mapper.Map(user));
+ // return Mapper.Map(userResult);
+ //}
+
+ /////
+ ///// Deletes the user.
+ /////
+ ///// The user.
+ /////
+ //[HttpDelete]
+ //public async Task DeleteUser([FromBody] UserViewModel user)
+ //{
+ // await UserManager.DeleteUser(Mapper.Map(user));
+ // return Ok();
+ //}
///
/// Gets all available claims in the system.
diff --git a/src/Ombi/IdentityConfig.cs b/src/Ombi/IdentityConfig.cs
new file mode 100644
index 000000000..f943e6f83
--- /dev/null
+++ b/src/Ombi/IdentityConfig.cs
@@ -0,0 +1,58 @@
+using System.Collections.Generic;
+using IdentityServer4.Models;
+
+namespace Ombi
+{
+ public class IdentityConfig
+ {
+ // scopes define the resources in your system
+ public static IEnumerable GetIdentityResources()
+ {
+ return new List
+ {
+ new IdentityResources.OpenId(),
+ new IdentityResources.Profile(),
+ new IdentityResource {
+ Name = "role",
+ UserClaims = new List {"role"}
+ }
+ };
+ }
+
+ public static IEnumerable GetApiResources()
+ {
+ return new List
+ {
+ new ApiResource("api", "API")
+ {
+ UserClaims = {"role", "name"},
+
+ }
+ };
+ }
+
+ // clients want to access resources (aka scopes)
+ public static IEnumerable GetClients()
+ {
+ // client credentials client
+ return new List
+ {
+ new Client
+ {
+ ClientId = "frontend",
+ AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
+
+ ClientSecrets =
+ {
+ new Secret("secret".Sha256()) // TODO read up on what this actually is
+ },
+ AllowedScopes =
+ {
+ "api",
+ },
+ AccessTokenType = AccessTokenType.Jwt
+ }
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi/Ombi.csproj b/src/Ombi/Ombi.csproj
index d8ef4e8c4..fb9ddf459 100644
--- a/src/Ombi/Ombi.csproj
+++ b/src/Ombi/Ombi.csproj
@@ -45,18 +45,21 @@
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/Ombi/Startup.Auth.cs b/src/Ombi/Startup.Auth.cs
deleted file mode 100644
index 0531e0130..000000000
--- a/src/Ombi/Startup.Auth.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using System.Security.Claims;
-using System.Security.Principal;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.Extensions.Options;
-using Microsoft.IdentityModel.Tokens;
-using Ombi.Auth;
-using Ombi.Core.IdentityResolver;
-
-namespace Ombi
-{
- public partial class Startup
- {
- ///
- /// A key...
- ///
- public SymmetricSecurityKey SigningKey;
- private void ConfigureAuth(IApplicationBuilder app, IOptions options)
- {
-
- var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(options.Value.SecretKey));
-
- var tokenProviderOptions = new TokenProviderOptions
- {
- Path = options.Value.TokenPath,
- Audience = options.Value.Audience,
- Issuer = options.Value.Issuer,
- SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
- IdentityResolver = GetIdentity
- };
-
- var tokenValidationParameters = new TokenValidationParameters
- {
- // The signing key must match!
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = signingKey,
- // Validate the JWT Issuer (iss) claim
- ValidateIssuer = true,
- ValidIssuer = options.Value.Issuer,
- // Validate the JWT Audience (aud) claim
- ValidateAudience = true,
- ValidAudience = options.Value.Audience,
- // Validate the token expiry
- ValidateLifetime = true,
- // If you want to allow a certain amount of clock drift, set that here:
- ClockSkew = TimeSpan.Zero,
- };
-
- app.UseJwtBearerAuthentication(new JwtBearerOptions
- {
- AutomaticAuthenticate = true,
- AutomaticChallenge = true,
- TokenValidationParameters = tokenValidationParameters,
- });
-
- app.UseMiddleware(Options.Create(tokenProviderOptions));
- }
-
-
- private async Task GetIdentity(string username, string password, IUserIdentityManager userIdentityManager)
- {
- var validLogin = await userIdentityManager.CredentialsValid(username, password);
- if (!validLogin)
- {
- return null;
- }
-
- var user = await userIdentityManager.GetUser(username);
- var claim = new ClaimsIdentity(new GenericIdentity(user.Username, "Token"), user.Claims);
- return claim;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs
index 45768cea0..5c1f6fa71 100644
--- a/src/Ombi/Startup.cs
+++ b/src/Ombi/Startup.cs
@@ -9,19 +9,23 @@ using Hangfire.SQLite;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.AspNetCore.StaticFiles;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
-using Ombi.Auth;
+using Microsoft.IdentityModel.Tokens;
using Ombi.Config;
using Ombi.DependencyInjection;
using Ombi.Mapping;
using Ombi.Schedule;
+using Ombi.Store.Context;
+using Ombi.Store.Entities;
using Serilog;
using Serilog.Events;
using StackExchange.Profiling;
@@ -66,9 +70,35 @@ namespace Ombi
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
+ services.AddDbContext(options =>
+ options.UseSqlite("Data Source=Ombi.db"));
+
+ services.AddIdentity()
+ .AddEntityFrameworkStores()
+ .AddDefaultTokenProviders();
+
+ services.AddIdentityServer()
+ .AddTemporarySigningCredential()
+ .AddInMemoryPersistedGrants()
+ .AddInMemoryIdentityResources(IdentityConfig.GetIdentityResources())
+ .AddInMemoryApiResources(IdentityConfig.GetApiResources())
+ .AddInMemoryClients(IdentityConfig.GetClients())
+ .AddAspNetIdentity();
+
+ services.Configure(options =>
+ {
+ options.Password.RequireDigit = false;
+ options.Password.RequiredLength = 1;
+ options.Password.RequireLowercase = false;
+ options.Password.RequireNonAlphanumeric = false;
+ options.Password.RequireUppercase = false;
+ });
+
services.AddMemoryCache();
+
services.AddMvc()
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
+
services.AddOmbiMappingProfile();
services.AddAutoMapper(expression =>
{
@@ -114,8 +144,9 @@ namespace Ombi
services.AddScoped(sp => sp.GetService().HttpContext.User);
- services.Configure(Configuration.GetSection("TokenAuthentication"));
+ //services.Configure(Configuration.GetSection("TokenAuthentication"));
services.Configure(Configuration.GetSection("ApplicationSettings"));
+ services.Configure(Configuration.GetSection("UserSettings"));
services.AddHangfire(x =>
{
@@ -140,6 +171,24 @@ namespace Ombi
{
//loggerFactory.AddConsole(Configuration.GetSection("Logging"));
//loggerFactory.AddDebug();
+ var options = (IOptions) app.ApplicationServices.GetService(
+ typeof(IOptions));
+
+ app.UseIdentity();
+ app.UseIdentityServer();
+ app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
+ {
+ Authority = options.Value.WebsiteUrl,
+ ApiName = "api",
+ ApiSecret = "secret",
+
+ EnableCaching = true,
+ CacheDuration = TimeSpan.FromMinutes(10), // that's the default
+ RequireHttpsMetadata = options.Value.UseHttps, // FOR DEV set to false
+ AutomaticAuthenticate = true,
+ AutomaticChallenge = true
+
+ });
loggerFactory.AddSerilog();
@@ -180,7 +229,7 @@ namespace Ombi
var jobSetup = (IJobSetup)app.ApplicationServices.GetService(typeof(IJobSetup));
jobSetup.Setup();
- ConfigureAuth(app, (IOptions)app.ApplicationServices.GetService(typeof(IOptions)));
+ //ConfigureAuth(app, (IOptions)app.ApplicationServices.GetService(typeof(IOptions)));
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".map"] = "application/octet-stream";
diff --git a/src/Ombi/appsettings.json b/src/Ombi/appsettings.json
index 4d21149d6..0c4cfe68f 100644
--- a/src/Ombi/appsettings.json
+++ b/src/Ombi/appsettings.json
@@ -8,6 +8,10 @@
"ApplicationSettings": {
"Verison": "{{VERSIONNUMBER}}"
},
+ "UserSettings": {
+ "WebsiteUrl": "http://localhost:52038",
+ "UseHttps": false
+ },
"TokenAuthentication": {
"SecretKey": "secretkey_secretkey123!",
"Issuer": "OmbiIssuer",
diff --git a/src/Ombi/bower.json b/src/Ombi/bower.json
deleted file mode 100644
index c7183c60e..000000000
--- a/src/Ombi/bower.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "ombi",
- "private": true,
- "dependencies": {
- "PACE": "pace#^1.0.2",
- "font-awesome": "^4.7.0"
- }
-}
-
\ No newline at end of file