From 24e424f00497af27a3435151c73bb86c447856c5 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Wed, 16 Aug 2017 14:31:35 +0100 Subject: [PATCH 1/4] Some small refresh token work #865 --- src/Ombi.DependencyInjection/IocExtensions.cs | 1 + src/Ombi.Store/Context/IOmbiContext.cs | 1 + src/Ombi.Store/Context/OmbiContext.cs | 1 + src/Ombi.Store/Entities/Tokens.cs | 14 ++++ ...r.cs => 20170811145836_Inital.Designer.cs} | 25 ++++++- ...617_Inital.cs => 20170811145836_Inital.cs} | 28 ++++++++ .../Migrations/OmbiContextModelSnapshot.cs | 23 +++++++ src/Ombi.Store/Repository/ITokenRepository.cs | 11 +-- src/Ombi.Store/Repository/TokenRepository.cs | 36 +++++----- src/Ombi/Controllers/TokenController.cs | 69 +++++++++++-------- src/Ombi/Models/UserAuthModel.cs | 1 + 11 files changed, 158 insertions(+), 52 deletions(-) create mode 100644 src/Ombi.Store/Entities/Tokens.cs rename src/Ombi.Store/Migrations/{20170801143617_Inital.Designer.cs => 20170811145836_Inital.Designer.cs} (96%) rename src/Ombi.Store/Migrations/{20170801143617_Inital.cs => 20170811145836_Inital.cs} (96%) diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 6126e188f..44edaf696 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -94,6 +94,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>)); } public static void RegisterServices(this IServiceCollection services) diff --git a/src/Ombi.Store/Context/IOmbiContext.cs b/src/Ombi.Store/Context/IOmbiContext.cs index 95f78a54a..c7e613a7c 100644 --- a/src/Ombi.Store/Context/IOmbiContext.cs +++ b/src/Ombi.Store/Context/IOmbiContext.cs @@ -29,5 +29,6 @@ namespace Ombi.Store.Context DbSet ChildRequests { get; set; } DbSet MovieIssues { get; set; } DbSet TvIssues { get; set; } + DbSet Tokens { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs index a87c41b28..c1364c87b 100644 --- a/src/Ombi.Store/Context/OmbiContext.cs +++ b/src/Ombi.Store/Context/OmbiContext.cs @@ -35,6 +35,7 @@ namespace Ombi.Store.Context public DbSet TvIssues { get; set; } public DbSet Audit { get; set; } + public DbSet Tokens { get; set; } public DbSet ApplicationConfigurations { get; set; } diff --git a/src/Ombi.Store/Entities/Tokens.cs b/src/Ombi.Store/Entities/Tokens.cs new file mode 100644 index 000000000..8d1dc2641 --- /dev/null +++ b/src/Ombi.Store/Entities/Tokens.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + public class Tokens : Entity + { + public string Token { get; set; } + public string UserId { get; set; } + + + [ForeignKey(nameof(UserId))] + public OmbiUser User { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Migrations/20170801143617_Inital.Designer.cs b/src/Ombi.Store/Migrations/20170811145836_Inital.Designer.cs similarity index 96% rename from src/Ombi.Store/Migrations/20170801143617_Inital.Designer.cs rename to src/Ombi.Store/Migrations/20170811145836_Inital.Designer.cs index 8c3ab43d2..80c66cbfd 100644 --- a/src/Ombi.Store/Migrations/20170801143617_Inital.Designer.cs +++ b/src/Ombi.Store/Migrations/20170811145836_Inital.Designer.cs @@ -10,7 +10,7 @@ using Ombi.Helpers; namespace Ombi.Store.Migrations { [DbContext(typeof(OmbiContext))] - [Migration("20170801143617_Inital")] + [Migration("20170811145836_Inital")] partial class Inital { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -449,6 +449,22 @@ namespace Ombi.Store.Migrations b.ToTable("TvRequests"); }); + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Token"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Tokens"); + }); + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => { b.Property("Id") @@ -581,6 +597,13 @@ namespace Ombi.Store.Migrations .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => { b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season") diff --git a/src/Ombi.Store/Migrations/20170801143617_Inital.cs b/src/Ombi.Store/Migrations/20170811145836_Inital.cs similarity index 96% rename from src/Ombi.Store/Migrations/20170801143617_Inital.cs rename to src/Ombi.Store/Migrations/20170811145836_Inital.cs index eff9e7734..d366494c9 100644 --- a/src/Ombi.Store/Migrations/20170801143617_Inital.cs +++ b/src/Ombi.Store/Migrations/20170811145836_Inital.cs @@ -296,6 +296,26 @@ namespace Ombi.Store.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateTable( + name: "Tokens", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Token = table.Column(nullable: true), + UserId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Tokens", x => x.Id); + table.ForeignKey( + name: "FK_Tokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + migrationBuilder.CreateTable( name: "PlexSeasonsContent", columns: table => new @@ -531,6 +551,11 @@ namespace Ombi.Store.Migrations table: "TvIssues", column: "TvId"); + migrationBuilder.CreateIndex( + name: "IX_Tokens_UserId", + table: "Tokens", + column: "UserId"); + migrationBuilder.CreateIndex( name: "IX_EpisodeRequests_SeasonId", table: "EpisodeRequests", @@ -583,6 +608,9 @@ namespace Ombi.Store.Migrations migrationBuilder.DropTable( name: "TvIssues"); + migrationBuilder.DropTable( + name: "Tokens"); + migrationBuilder.DropTable( name: "EpisodeRequests"); diff --git a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs index b67c5df06..ed875997e 100644 --- a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs @@ -448,6 +448,22 @@ namespace Ombi.Store.Migrations b.ToTable("TvRequests"); }); + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Token"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Tokens"); + }); + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => { b.Property("Id") @@ -580,6 +596,13 @@ namespace Ombi.Store.Migrations .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => { b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season") diff --git a/src/Ombi.Store/Repository/ITokenRepository.cs b/src/Ombi.Store/Repository/ITokenRepository.cs index 9d15c9d6a..cae11dcb5 100644 --- a/src/Ombi.Store/Repository/ITokenRepository.cs +++ b/src/Ombi.Store/Repository/ITokenRepository.cs @@ -1,12 +1,13 @@ using System; +using System.Linq; using System.Threading.Tasks; using Ombi.Store.Entities; namespace Ombi.Store.Repository { - //public interface ITokenRepository - //{ - // Task CreateToken(EmailTokens token); - // Task GetToken(Guid tokenId); - //} + public interface ITokenRepository + { + Task CreateToken(Tokens token); + IQueryable GetToken(string tokenId); + } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/TokenRepository.cs b/src/Ombi.Store/Repository/TokenRepository.cs index 645f515dd..d766c5690 100644 --- a/src/Ombi.Store/Repository/TokenRepository.cs +++ b/src/Ombi.Store/Repository/TokenRepository.cs @@ -2,29 +2,29 @@ using Ombi.Store.Context; using Ombi.Store.Entities; using System; +using System.Linq; using System.Threading.Tasks; namespace Ombi.Store.Repository { - //public class TokenRepository : ITokenRepository - //{ - // public TokenRepository(IOmbiContext db) - // { - // Db = db; - // } + public class TokenRepository : ITokenRepository + { + public TokenRepository(IOmbiContext db) + { + Db = db; + } - // private IOmbiContext Db { get; } + private IOmbiContext Db { get; } - // public async Task CreateToken(EmailTokens token) - // { - // token.Token = Guid.NewGuid(); - // await Db.EmailTokens.AddAsync(token); - // await Db.SaveChangesAsync(); - // } + public async Task CreateToken(Tokens token) + { + await Db.Tokens.AddAsync(token); + await Db.SaveChangesAsync(); + } - // public async Task GetToken(Guid tokenId) - // { - // return await Db.EmailTokens.FirstOrDefaultAsync(x => x.Token == tokenId); - // } - //} + public IQueryable GetToken(string tokenId) + { + return Db.Tokens.Where(x => x.Token == tokenId); + } + } } diff --git a/src/Ombi/Controllers/TokenController.cs b/src/Ombi/Controllers/TokenController.cs index d65882110..4d92dfaa1 100644 --- a/src/Ombi/Controllers/TokenController.cs +++ b/src/Ombi/Controllers/TokenController.cs @@ -20,18 +20,20 @@ namespace Ombi.Controllers public class TokenController { public TokenController(UserManager um, IOptions ta, - IApplicationConfigRepository config, IAuditRepository audit) + IApplicationConfigRepository config, IAuditRepository audit, ITokenRepository token) { - UserManager = um; - TokenAuthenticationOptions = ta.Value; - Config = config; - Audit = audit; + _userManager = um; + _tokenAuthenticationOptions = ta.Value; + _config = config; + _audit = audit; + _token = token; } - private TokenAuthentication TokenAuthenticationOptions { get; } - private IApplicationConfigRepository Config { get; } - private IAuditRepository Audit { get; } - private UserManager UserManager { get; } + private readonly TokenAuthentication _tokenAuthenticationOptions; + private IApplicationConfigRepository _config; + private readonly IAuditRepository _audit; + private readonly ITokenRepository _token; + private readonly UserManager _userManager; /// /// Gets the token. @@ -41,30 +43,20 @@ namespace Ombi.Controllers [HttpPost] public async Task GetToken([FromBody] UserAuthModel model) { - await Audit.Record(AuditType.None, AuditArea.Authentication, + await _audit.Record(AuditType.None, AuditArea.Authentication, $"Username {model.Username} attempting to authenticate"); - var user = await UserManager.FindByNameAsync(model.Username); + var user = await _userManager.FindByNameAsync(model.Username); if (user == null) { - return null; + return new UnauthorizedResult(); } // Verify Password - if ((await UserManager.CheckPasswordAsync(user, model.Password))) + if (await _userManager.CheckPasswordAsync(user, model.Password)) { - // Get the url - var url = Config.Get(ConfigurationTypes.Url); - var port = Config.Get(ConfigurationTypes.Port); - -#if !DEBUG - var audience = $"{url}:{port}"; -#else - - var audience = $"http://localhost:52038/"; -#endif - var roles = await UserManager.GetRolesAsync(user); + var roles = await _userManager.GetRolesAsync(user); var claims = new List { @@ -74,7 +66,7 @@ namespace Ombi.Controllers }; claims.AddRange(roles.Select(role => new Claim("role", role))); - var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(TokenAuthenticationOptions.SecretKey)); + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenAuthenticationOptions.SecretKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( @@ -83,15 +75,21 @@ namespace Ombi.Controllers signingCredentials: creds, audience: "Ombi", issuer:"Ombi" ); + var accessToken = new JwtSecurityTokenHandler().WriteToken(token); + if (model.RememberMe) + { + // Save the token so we can refresh it later + await _token.CreateToken(new Tokens() {Token = accessToken, User = user}); + } return new JsonResult(new { - access_token = new JwtSecurityTokenHandler().WriteToken(token), + access_token = accessToken, expiration = token.ValidTo }); } - return null; + return new UnauthorizedResult(); } /// @@ -101,10 +99,25 @@ namespace Ombi.Controllers /// /// [HttpPost("refresh")] - public async Task RefreshToken([FromBody] UserAuthModel model) + public async Task RefreshToken([FromBody] TokenRefresh token) { + + // Check if token exists + var dbToken = _token.GetToken(token.Token).FirstOrDefault(); + if (dbToken == null) + { + return new UnauthorizedResult(); + } + + throw new NotImplementedException(); } + public class TokenRefresh + { + public string Token { get; set; } + public string Userename { get; set; } + } + } } \ No newline at end of file diff --git a/src/Ombi/Models/UserAuthModel.cs b/src/Ombi/Models/UserAuthModel.cs index 4e16af0b8..0148a0729 100644 --- a/src/Ombi/Models/UserAuthModel.cs +++ b/src/Ombi/Models/UserAuthModel.cs @@ -4,5 +4,6 @@ { public string Username { get; set; } public string Password { get; set; } + public bool RememberMe { get; set; } } } \ No newline at end of file From 0d1ee148c78e0db9c2ef8414c993823c1d001921 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Fri, 18 Aug 2017 08:47:55 +0100 Subject: [PATCH 2/4] Fixed the user token issue #865 --- src/Ombi/Controllers/TokenController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Ombi/Controllers/TokenController.cs b/src/Ombi/Controllers/TokenController.cs index 4d92dfaa1..fa10ecf77 100644 --- a/src/Ombi/Controllers/TokenController.cs +++ b/src/Ombi/Controllers/TokenController.cs @@ -61,7 +61,8 @@ namespace Ombi.Controllers var claims = new List { new Claim(JwtRegisteredClaimNames.Sub, user.UserName), - new Claim("name", user.UserName), + new Claim(ClaimTypes.NameIdentifier, user.Id), + new Claim(ClaimTypes.Name, user.UserName), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; claims.AddRange(roles.Select(role => new Claim("role", role))); From 9f69ab50063918bc480bc725e61ba9a94ada90f8 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Fri, 18 Aug 2017 09:05:33 +0100 Subject: [PATCH 3/4] enable diagnostic on build #865 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 8b03c042a..44613fdaf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ install: # Get the latest stable version of Node.js or io.js - ps: Install-Product node $env:nodejs_version build_script: - - ps: ./build.ps1 + - ps: ./build.ps1 -Verbosity Diagnostic after_build: - cmd: >- From c2cd2b9876cb7bb158e1e5f8ba696a4b402503b3 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Fri, 18 Aug 2017 10:12:35 +0100 Subject: [PATCH 4/4] Change Os to VS2015 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 44613fdaf..f6a14f1b0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ version: 3.0.{build} configuration: Release -os: Visual Studio 2017 +os: Visual Studio 2015 environment: nodejs_version: "7.8.0"