diff --git a/src/Project/Controllers/DataSourceController.cs b/src/Project/Controllers/DataSourceController.cs index 7865f91389069eab34cc88698991a8d3311a67a5..c4d34714cc90faf0d90fcdba4317f97f5b30b83e 100644 --- a/src/Project/Controllers/DataSourceController.cs +++ b/src/Project/Controllers/DataSourceController.cs @@ -1,8 +1,12 @@ -using Coscine.Api.Project.ReturnObjects; +using Coscine.Api.Project.Models; +using Coscine.Api.Project.ReturnObjects; +using Coscine.ApiCommons; using Coscine.ApiCommons.Utils; using Coscine.Configuration; +using Coscine.Database.Model; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; @@ -16,58 +20,118 @@ namespace Coscine.Api.Project.Controllers { private readonly IConfiguration _configuration; private readonly JWTHandler _jwtHandler; - private readonly static HttpClient _client = new HttpClient(); + private static readonly HttpClient _client = new HttpClient(); + private readonly Authenticator _authenticator; + private readonly ResourceModel _resourceModel; + public DataSourceController() { - _configuration = new ConsulConfiguration(); + _configuration = Program.Configuration; _jwtHandler = new JWTHandler(_configuration); + _authenticator = new Authenticator(this, _configuration); + _resourceModel = new ResourceModel(); } - [HttpGet("[controller]/{*path}")] - public async Task<IActionResult> Get(string path) + + // inferring a ../ (urlencoded) can manipulate the url. + // However the constructed signature for s3 won't match and it will not be resolved. + // This may be a problem for other provider! + [HttpGet("[controller]/{resourceId}/{*path}")] + public async Task<IActionResult> Get(string resourceId, string path) { - // inferring a ../ (urlencoded) can manipulate the url. - // However the constructed signature for s3 won't match and it will not be resolved. - // If the path is null, an empty string is added. - string url = $"http://localhost:7777/v1/resources/0/providers/rds/{path}"; - var request = new HttpRequestMessage(HttpMethod.Get, url); - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", BuildAuthHeader()); + if (!Guid.TryParse(resourceId, out Guid resouceGuid)) + { + return BadRequest($"{resourceId} is not a guid."); + } - // Thread safe according to msdn and HttpCompletionOption sets it to get only headers first. - var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); - if (response.IsSuccessStatusCode) + Resource resource; + try { - if (response.Content.Headers.Contains("Content-Disposition")) - { - return File(await response.Content.ReadAsStreamAsync(), - response.Content.Headers.GetValues("Content-Type").First()); - } - else + resource = _resourceModel.GetById(resouceGuid); + if (resource == null) { - var data = JObject.Parse(await response.Content.ReadAsStringAsync())["data"]; - return Ok(new WaterbutlerObject(path, data)); + return NotFound($"Could not find resource with id: {resourceId}"); } } - else + catch (Exception) { - if (response.StatusCode == System.Net.HttpStatusCode.NotFound) - { - return NotFound($"Coukd not find object for: \"{path}\"."); - } - else - if (response.StatusCode == System.Net.HttpStatusCode.Forbidden) + return NotFound($"Could not find resource with id: {resourceId}"); + } + + // Temporary +#if (!DEBUG) + var user = _authenticator.GetUserFromToken(); + if (!_resourceModel.OwnsResource(user, resource)) + { + return Forbid($"The user does not own the resource {resourceId}"); + } +#endif + + if (resource.Type == null) + { + ResourceTypeModel resourceTypeModel = new ResourceTypeModel(); + resource.Type = resourceTypeModel.GetById(resource.TypeId); + } + + string authHeader = null; + + if (resource.Type.DisplayName.ToLower() == "rds") + { + authHeader = BuildRdsAuthHeader(); + } + else if (resource.Type.DisplayName.ToLower() == "gitlab") + { + authHeader = BuildGitlabAuthHeader(); + } + + if (authHeader != null) + { + // If the path is null, an empty string is added. + string url = $"{_configuration.GetString("coscine/global/waterbutler_url")}{resource.Type.DisplayName.ToLower()}/{path}"; + + var request = new HttpRequestMessage(HttpMethod.Get, url); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authHeader); + + // Thread safe according to msdn and HttpCompletionOption sets it to get only headers first. + var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + if (response.IsSuccessStatusCode) { - return Forbid($"Not allowed to access the datasource."); + if (response.Content.Headers.Contains("Content-Disposition")) + { + return File(await response.Content.ReadAsStreamAsync(), + response.Content.Headers.GetValues("Content-Type").First()); + } + else + { + var data = JObject.Parse(await response.Content.ReadAsStringAsync())["data"]; + return Ok(new WaterbutlerObject(path, data)); + } } else { - return BadRequest($"Error in communication with waterbutler: {response.StatusCode}"); + if (response.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return NotFound($"Could not find object for: \"{path}\"."); + } + else + if (response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + return Forbid($"Not allowed to access the datasource."); + } + else + { + return BadRequest($"Error in communication with waterbutler: {response.StatusCode}"); + } } } + else + { + return BadRequest($"No provider for: \"{resource.Type.DisplayName}\"."); + } } - private string BuildAuthHeader() + private string BuildRdsAuthHeader() { var auth = new Dictionary<string, object>(); @@ -97,5 +161,10 @@ namespace Coscine.Api.Project.Controllers return _jwtHandler.GenerateJwtToken(payload); } + + private string BuildGitlabAuthHeader() + { + return null; + } } }