Commit 6abd38a2 authored by David Schimmel's avatar David Schimmel

Merge branch 'Topic/209-connectToRds' into 'master'

Topic/209 connect to rds

See merge request coscine/api/project!9
parents ba253746 bace1bb3
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;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Controllers
{
public class DataSourceController : Controller
{
private readonly IConfiguration _configuration;
private readonly JWTHandler _jwtHandler;
private static readonly HttpClient _client = new HttpClient();
private readonly Authenticator _authenticator;
private readonly ResourceModel _resourceModel;
public DataSourceController()
{
_configuration = Program.Configuration;
_jwtHandler = new JWTHandler(_configuration);
_authenticator = new Authenticator(this, _configuration);
_resourceModel = new ResourceModel();
}
// 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)
{
if (!Guid.TryParse(resourceId, out Guid resouceGuid))
{
return BadRequest($"{resourceId} is not a guid.");
}
Resource resource;
try
{
resource = _resourceModel.GetById(resouceGuid);
if (resource == null)
{
return NotFound($"Could not find resource with id: {resourceId}");
}
}
catch (Exception)
{
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(resource.ExternalId);
}
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)
{
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
{
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 BuildRdsAuthHeader(string bucketname)
{
var auth = new Dictionary<string, object>();
var credentials = new Dictionary<string, object>
{
{ "access_key", _configuration.GetString("coscine/global/rds_access_key") },
{ "secret_key", _configuration.GetString("coscine/global/rds_secret_key") }
};
var settings = new Dictionary<string, object>
{
{ "bucket", bucketname }
};
var data = new Dictionary<string, object>
{
{ "auth", auth },
{ "credentials", credentials },
{ "settings", settings },
{ "callback_url", "rwth-aachen.de" }
};
var payload = new JwtPayload
{
{ "data", data }
};
return _jwtHandler.GenerateJwtToken(payload);
}
private string BuildGitlabAuthHeader()
{
return null;
}
}
}
......@@ -563,6 +563,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\DataSourceController.cs" />
<Compile Include="Controllers\ProjectController.cs" />
<Compile Include="Controllers\ResourceController.cs" />
<Compile Include="Controllers\ResourceTypeController.cs" />
......@@ -585,6 +586,7 @@
<Compile Include="ReturnObjects\ResourceTypeObject.cs" />
<Compile Include="ReturnObjects\RoleObject.cs" />
<Compile Include="ReturnObjects\UserObject.cs" />
<Compile Include="ReturnObjects\WaterbutlerFolder.cs" />
<Compile Include="Startup.cs" />
</ItemGroup>
<ItemGroup>
......
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
namespace Coscine.Api.Project.ReturnObjects
{
public class WaterbutlerObject
{
public bool IsFolder { get; set; } = false;
public string Absolutepath { get; set; } = null;
public string Name { get; set; } = null;
// Shallow! Only one level deep.
// Should the folder contain additional folders, they will be empty/null.
public List<WaterbutlerObject> Content { get; set; } = null;
public WaterbutlerObject()
{
}
public WaterbutlerObject(string path, JToken data)
{
Absolutepath = string.IsNullOrWhiteSpace(path) ? "/" : $"/{path}";
Content = new List<WaterbutlerObject>();
IsFolder = true;
if (data == null)
{
throw new ArgumentNullException("The data for the WaterbutlerFolder cannot be null.");
}
foreach (var obj in data)
{
if (obj["type"].ToObject<string>() == "files")
{
Content.Add(new WaterbutlerObject
{
IsFolder = obj["attributes"]["kind"].ToObject<string>() == "folder",
Absolutepath = obj["attributes"]["path"].ToObject<string>(),
Name = obj["attributes"]["name"].ToObject<string>()
});
}
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment