Adding authorization guards on the API

This commit is contained in:
Zoe Roux 2020-03-29 22:03:06 +02:00
parent f54dc6b282
commit 90cc54446a
13 changed files with 74 additions and 8 deletions

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Net;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using Kyoo.Api; using Kyoo.Api;
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
@ -75,7 +77,30 @@ namespace Kyoo
.AddInMemoryApiResources(IdentityContext.GetApis()) .AddInMemoryApiResources(IdentityContext.GetApis())
.AddAspNetIdentity<User>() .AddAspNetIdentity<User>()
.AddProfileService<AccountController>() .AddProfileService<AccountController>()
.AddDeveloperSigningCredential(); .AddDeveloperSigningCredential(); // TODO remove the developer signin
services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToAccessDenied = context =>
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return Task.CompletedTask;
};
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return Task.CompletedTask;
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("Read", policy => policy.RequireClaim("read"));
options.AddPolicy("Write", policy => policy.RequireClaim("write"));
options.AddPolicy("Play", policy => policy.RequireClaim("play"));
options.AddPolicy("Download", policy => policy.RequireClaim("download"));
options.AddPolicy("Admin", policy => policy.RequireClaim("admin"));
});
services.AddScoped<ILibraryManager, LibraryManager>(); services.AddScoped<ILibraryManager, LibraryManager>();
services.AddScoped<ICrawler, Crawler>(); services.AddScoped<ICrawler, Crawler>();

View File

@ -52,6 +52,12 @@ namespace Kyoo.Api
private readonly UserManager<User> _userManager; private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager; private readonly SignInManager<User> _signInManager;
private readonly string _picturePath; private readonly string _picturePath;
public Claim[] defaultClaims =
{
new Claim("read", ""),
new Claim("play", "")
}; // TODO should add this field on the server's configuration page.
public AccountController(UserManager<User> userManager, SignInManager<User> siginInManager, IConfiguration configuration) public AccountController(UserManager<User> userManager, SignInManager<User> siginInManager, IConfiguration configuration)
{ {
@ -73,6 +79,7 @@ namespace Kyoo.Api
return BadRequest(result.Errors); return BadRequest(result.Errors);
string otac = account.GenerateOTAC(TimeSpan.FromMinutes(1)); string otac = account.GenerateOTAC(TimeSpan.FromMinutes(1));
await _userManager.UpdateAsync(account); await _userManager.UpdateAsync(account);
await _userManager.AddClaimsAsync(account, defaultClaims);
return Ok(otac); return Ok(otac);
} }
@ -118,7 +125,7 @@ namespace Kyoo.Api
new Claim("username", user.UserName), new Claim("username", user.UserName),
new Claim("picture", $"api/account/picture/{user.UserName}") new Claim("picture", $"api/account/picture/{user.UserName}")
}; };
context.IssuedClaims.AddRange(claims); context.IssuedClaims.AddRange(claims);
} }
} }

View File

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Threading; using System.Threading;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
{ {
@ -9,6 +10,7 @@ namespace Kyoo.Api
public class AdminController : ControllerBase public class AdminController : ControllerBase
{ {
[HttpGet("scan")] [HttpGet("scan")]
[Authorize(Policy="Admin")]
public IActionResult ScanLibrary([FromServices] ICrawler crawler) public IActionResult ScanLibrary([FromServices] ICrawler crawler)
{ {
// The crawler is destroyed before the completion of this task. // The crawler is destroyed before the completion of this task.

View File

@ -2,6 +2,7 @@
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
{ {
@ -17,6 +18,7 @@ namespace Kyoo.Api
} }
[HttpGet("{collectionSlug}")] [HttpGet("{collectionSlug}")]
[Authorize(Policy="Read")]
public ActionResult<Collection> GetShows(string collectionSlug) public ActionResult<Collection> GetShows(string collectionSlug)
{ {
Collection collection = _libraryManager.GetCollection(collectionSlug); Collection collection = _libraryManager.GetCollection(collectionSlug);

View File

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
{ {
@ -18,6 +19,7 @@ namespace Kyoo.Api
} }
[HttpGet("{showSlug}/season/{seasonNumber}")] [HttpGet("{showSlug}/season/{seasonNumber}")]
[Authorize(Policy="Read")]
public ActionResult<IEnumerable<Episode>> GetEpisodesForSeason(string showSlug, long seasonNumber) public ActionResult<IEnumerable<Episode>> GetEpisodesForSeason(string showSlug, long seasonNumber)
{ {
IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug, seasonNumber); IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug, seasonNumber);
@ -29,6 +31,7 @@ namespace Kyoo.Api
} }
[HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")] [HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")]
[Authorize(Policy="Read")]
[JsonDetailed] [JsonDetailed]
public ActionResult<Episode> GetEpisode(string showSlug, long seasonNumber, long episodeNumber) public ActionResult<Episode> GetEpisode(string showSlug, long seasonNumber, long episodeNumber)
{ {

View File

@ -1,5 +1,6 @@
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api namespace Kyoo.Api
@ -16,6 +17,7 @@ namespace Kyoo.Api
} }
[HttpGet("{peopleSlug}")] [HttpGet("{peopleSlug}")]
[Authorize(Policy="Read")]
public ActionResult<Collection> GetPeople(string peopleSlug) public ActionResult<Collection> GetPeople(string peopleSlug)
{ {
People people = _libraryManager.GetPeopleBySlug(peopleSlug); People people = _libraryManager.GetPeopleBySlug(peopleSlug);

View File

@ -1,5 +1,6 @@
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api namespace Kyoo.Api
@ -16,6 +17,7 @@ namespace Kyoo.Api
} }
[HttpGet("{query}")] [HttpGet("{query}")]
[Authorize(Policy="Read")]
public ActionResult<SearchResult> Search(string query) public ActionResult<SearchResult> Search(string query)
{ {
SearchResult result = new SearchResult SearchResult result = new SearchResult

View File

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic; using System.Collections.Generic;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
{ {
@ -18,12 +19,14 @@ namespace Kyoo.Api
} }
[HttpGet] [HttpGet]
[Authorize(Policy="Read")]
public IEnumerable<Show> GetShows() public IEnumerable<Show> GetShows()
{ {
return _libraryManager.GetShows(); return _libraryManager.GetShows();
} }
[HttpGet("{slug}")] [HttpGet("{slug}")]
[Authorize(Policy="Read")]
[JsonDetailed] [JsonDetailed]
public ActionResult<Show> GetShow(string slug) public ActionResult<Show> GetShow(string slug)
{ {

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
{ {
@ -22,6 +23,7 @@ namespace Kyoo.Api
} }
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")] [HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")]
[Authorize(Policy="Play")]
public IActionResult GetSubtitle(string showSlug, int seasonNumber, int episodeNumber, string identifier, string extension) public IActionResult GetSubtitle(string showSlug, int seasonNumber, int episodeNumber, string identifier, string extension)
{ {
string languageTag = identifier.Length == 3 ? identifier.Substring(0, 3) : null; string languageTag = identifier.Length == 3 ? identifier.Substring(0, 3) : null;
@ -57,6 +59,7 @@ namespace Kyoo.Api
} }
[HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Admin")]
public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber) public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber)
{ {
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber); Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
@ -73,6 +76,7 @@ namespace Kyoo.Api
} }
[HttpGet("extract/{showSlug}")] [HttpGet("extract/{showSlug}")]
[Authorize(Policy="Admin")]
public async Task<string> ExtractSubtitle(string showSlug) public async Task<string> ExtractSubtitle(string showSlug)
{ {
IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug); IEnumerable<Episode> episodes = _libraryManager.GetEpisodes(showSlug);

View File

@ -2,6 +2,7 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using System.IO; using System.IO;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
{ {
@ -18,6 +19,7 @@ namespace Kyoo.Api
} }
[HttpGet("poster/{showSlug}")] [HttpGet("poster/{showSlug}")]
[Authorize(Policy="Read")]
public IActionResult GetShowThumb(string showSlug) public IActionResult GetShowThumb(string showSlug)
{ {
string path = _libraryManager.GetShowBySlug(showSlug)?.Path; string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
@ -27,11 +29,12 @@ namespace Kyoo.Api
string thumb = Path.Combine(path, "poster.jpg"); string thumb = Path.Combine(path, "poster.jpg");
if (System.IO.File.Exists(thumb)) if (System.IO.File.Exists(thumb))
return new PhysicalFileResult(thumb, "image/jpg"); return new PhysicalFileResult(Path.GetFullPath(thumb), "image/jpg");
return NotFound(); return NotFound();
} }
[HttpGet("logo/{showSlug}")] [HttpGet("logo/{showSlug}")]
[Authorize(Policy="Read")]
public IActionResult GetShowLogo(string showSlug) public IActionResult GetShowLogo(string showSlug)
{ {
string path = _libraryManager.GetShowBySlug(showSlug)?.Path; string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
@ -41,11 +44,12 @@ namespace Kyoo.Api
string thumb = Path.Combine(path, "logo.png"); string thumb = Path.Combine(path, "logo.png");
if (System.IO.File.Exists(thumb)) if (System.IO.File.Exists(thumb))
return new PhysicalFileResult(thumb, "image/jpg"); return new PhysicalFileResult(Path.GetFullPath(thumb), "image/jpg");
return NotFound(); return NotFound();
} }
[HttpGet("backdrop/{showSlug}")] [HttpGet("backdrop/{showSlug}")]
[Authorize(Policy="Read")]
public IActionResult GetShowBackdrop(string showSlug) public IActionResult GetShowBackdrop(string showSlug)
{ {
string path = _libraryManager.GetShowBySlug(showSlug)?.Path; string path = _libraryManager.GetShowBySlug(showSlug)?.Path;
@ -55,21 +59,23 @@ namespace Kyoo.Api
string thumb = Path.Combine(path, "backdrop.jpg"); string thumb = Path.Combine(path, "backdrop.jpg");
if (System.IO.File.Exists(thumb)) if (System.IO.File.Exists(thumb))
return new PhysicalFileResult(thumb, "image/jpg"); return new PhysicalFileResult(Path.GetFullPath(thumb), "image/jpg");
return NotFound(); return NotFound();
} }
[HttpGet("peopleimg/{peopleSlug}")] [HttpGet("peopleimg/{peopleSlug}")]
[Authorize(Policy="Read")]
public IActionResult GetPeopleIcon(string peopleSlug) public IActionResult GetPeopleIcon(string peopleSlug)
{ {
string thumbPath = Path.Combine(_peoplePath, peopleSlug + ".jpg"); string thumbPath = Path.Combine(_peoplePath, peopleSlug + ".jpg");
if (!System.IO.File.Exists(thumbPath)) if (!System.IO.File.Exists(thumbPath))
return NotFound(); return NotFound();
return new PhysicalFileResult(thumbPath, "image/jpg"); return new PhysicalFileResult(Path.GetFullPath(thumbPath), "image/jpg");
} }
[HttpGet("thumb/{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("thumb/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Read")]
public IActionResult GetEpisodeThumb(string showSlug, long seasonNumber, long episodeNumber) public IActionResult GetEpisodeThumb(string showSlug, long seasonNumber, long episodeNumber)
{ {
string path = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber)?.Path; string path = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber)?.Path;
@ -79,7 +85,7 @@ namespace Kyoo.Api
string thumb = Path.ChangeExtension(path, "jpg"); string thumb = Path.ChangeExtension(path, "jpg");
if (System.IO.File.Exists(thumb)) if (System.IO.File.Exists(thumb))
return new PhysicalFileResult(thumb, "image/jpg"); return new PhysicalFileResult(Path.GetFullPath(thumb), "image/jpg");
return NotFound(); return NotFound();
} }
} }

View File

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
{ {
@ -23,6 +24,7 @@ namespace Kyoo.Api
} }
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Play")]
public IActionResult Index(string showSlug, long seasonNumber, long episodeNumber) public IActionResult Index(string showSlug, long seasonNumber, long episodeNumber)
{ {
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber); WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
@ -33,6 +35,7 @@ namespace Kyoo.Api
} }
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Play")]
public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber) public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber)
{ {
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber); WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
@ -55,6 +58,7 @@ namespace Kyoo.Api
} }
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Play")]
public async Task<IActionResult> Transcode(string showSlug, long seasonNumber, long episodeNumber) public async Task<IActionResult> Transcode(string showSlug, long seasonNumber, long episodeNumber)
{ {
WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber); WatchItem episode = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
@ -69,6 +73,7 @@ namespace Kyoo.Api
[HttpGet("{movieSlug}")] [HttpGet("{movieSlug}")]
[Authorize(Policy="Play")]
public IActionResult Index(string movieSlug) public IActionResult Index(string movieSlug)
{ {
WatchItem episode = _libraryManager.GetMovieWatchItem(movieSlug); WatchItem episode = _libraryManager.GetMovieWatchItem(movieSlug);
@ -79,6 +84,7 @@ namespace Kyoo.Api
} }
[HttpGet("transmux/{movieSlug}")] [HttpGet("transmux/{movieSlug}")]
[Authorize(Policy="Play")]
public async Task<IActionResult> Transmux(string movieSlug) public async Task<IActionResult> Transmux(string movieSlug)
{ {
WatchItem episode = _libraryManager.GetMovieWatchItem(movieSlug); WatchItem episode = _libraryManager.GetMovieWatchItem(movieSlug);
@ -92,6 +98,7 @@ namespace Kyoo.Api
} }
[HttpGet("transcode/{movieSlug}")] [HttpGet("transcode/{movieSlug}")]
[Authorize(Policy="Play")]
public async Task<IActionResult> Transcode(string movieSlug) public async Task<IActionResult> Transcode(string movieSlug)
{ {
WatchItem episode = _libraryManager.GetMovieWatchItem(movieSlug); WatchItem episode = _libraryManager.GetMovieWatchItem(movieSlug);

View File

@ -1,5 +1,6 @@
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api namespace Kyoo.Api
@ -16,6 +17,7 @@ namespace Kyoo.Api
} }
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Read")]
public ActionResult<WatchItem> Index(string showSlug, long seasonNumber, long episodeNumber) public ActionResult<WatchItem> Index(string showSlug, long seasonNumber, long episodeNumber)
{ {
WatchItem item = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber); WatchItem item = _libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
@ -27,6 +29,7 @@ namespace Kyoo.Api
} }
[HttpGet("{movieSlug}")] [HttpGet("{movieSlug}")]
[Authorize(Policy="Read")]
public ActionResult<WatchItem> Index(string movieSlug) public ActionResult<WatchItem> Index(string movieSlug)
{ {
WatchItem item = _libraryManager.GetMovieWatchItem(movieSlug); WatchItem item = _libraryManager.GetMovieWatchItem(movieSlug);

@ -1 +1 @@
Subproject commit 5d6a7cf319ce57dc5cf12a10e0195af5705b566f Subproject commit 04e92944eeb2f5617834253d01ef312fee46e435