You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
16 KiB
344 lines
16 KiB
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Azure.Cosmos;
|
|
using Microsoft.Azure.Functions.Worker.Http;
|
|
using Microsoft.Azure.Functions.Worker;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace CDP
|
|
{
|
|
public class CDPLite
|
|
{
|
|
private readonly ILogger<CDPLite> _logger;
|
|
public static string FileAuditContainer = "FileAudits";
|
|
public static string UserAuditContainer = "UserAudits";
|
|
public static string GroupAuditContainer = "GroupAudits";
|
|
public static string TenantAuditContainer = "TenantAudits";
|
|
|
|
public CDPLite(ILogger<CDPLite> log)
|
|
{
|
|
_logger = log;
|
|
}
|
|
|
|
/*internal async Task<IActionResult> AddFilesBatchedInternal(AddFileBatchedDto dto)
|
|
{
|
|
string userId = Helpers.HashAndShortenText(dto.Email.ToLower());
|
|
string jobId = Guid.NewGuid().ToString();
|
|
List<KeyVaultEvent> vaultEvents = new List<KeyVaultEvent>();
|
|
//List<AuditEventMetadata> auditEvents = new List<AuditEventMetadata>();
|
|
List<FileRecord> fileRecords = new List<FileRecord>();
|
|
for (int i = 0; i < dto.Count; i++)
|
|
{
|
|
string fileId = Guid.NewGuid().ToString();
|
|
string fileName = dto.FileNames[i];
|
|
string aesKey = Helpers.GenerateAES256KeyToBase64();
|
|
//string message = string.Format($"{dto.Email} protected {fileName} file having {fileId} id.");
|
|
KeyVaultEvent vaultEvent = new KeyVaultEvent { AESKey = aesKey, FileId = fileId };
|
|
//AuditEventMetadata auditEvent = new AuditEventMetadata { Action = "Addded", FileId = fileId, FileName = dto.FileNames[i], Message = message, UserId = userId };
|
|
//auditEvents.Add(auditEvent);
|
|
vaultEvents.Add(vaultEvent);
|
|
|
|
AccessPolicy ac = new AccessPolicy()
|
|
{
|
|
Access = "Owner",
|
|
Key = aesKey,
|
|
Email = dto.Email
|
|
};
|
|
FileRecord fr = await CDPDB.UpsertFile(dto.AppKey, fileId, fileName, userId, "", ac);
|
|
fileRecords.Add(fr);
|
|
}
|
|
List<Job> jobs = new List<Job>();
|
|
Job vaultJob = await AddKeyVaultBatchedEvent(vaultEvents, dto.AppKey);
|
|
//Job auditJob = await AddAuditsBatchedEvent(auditEvents, dto.AppKey);
|
|
//jobs.Add(auditJob);
|
|
jobs.Add(vaultJob);
|
|
await MetaProcessor.PublishBatchJobs(jobs);
|
|
return new OkObjectResult(fileRecords);
|
|
|
|
}*/
|
|
|
|
|
|
internal async Task<IActionResult> AddFileInternal(AddFileDto dto, bool useKeyVaultEvent = false)
|
|
{
|
|
string fileId = Guid.NewGuid().ToString();
|
|
|
|
string userId = Helpers.HashAndShortenText(dto.Email.ToLower());
|
|
string fileName = dto.FileName;
|
|
string aesKey = Helpers.GenerateAES256KeyToBase64();
|
|
|
|
// the KeyVault is slow for some reason and while it's dangerous to return a key
|
|
// before we're sure it got added to the database...I'm going to do it anyway.
|
|
if (useKeyVaultEvent)
|
|
{
|
|
await AddKeyVaultEvent(fileId, aesKey, dto.AppKey);
|
|
}
|
|
else
|
|
{
|
|
await Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
KeyVaultService kvs = new KeyVaultService(Constants.KeyVaultURI);
|
|
await kvs.SetSecretAsync(fileId, aesKey);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e);
|
|
}
|
|
});
|
|
}
|
|
|
|
// when you add a file, you have rights to manage access to it.
|
|
AccessPolicy ac = new AccessPolicy()
|
|
{
|
|
Access = "Owner",
|
|
Key = aesKey,
|
|
Email = dto.Email
|
|
};
|
|
|
|
// since we're generating a new file id, a new entry will always be created.
|
|
FileRecord fr = await CDPDB.UpsertFile(dto.AppKey, fileId, fileName, userId, "", ac);
|
|
|
|
string message = string.Format($"{dto.Email} protected {fileName} file having {fileId} id.");
|
|
string action = "Added";
|
|
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, fileId, fileName, userId, dto.GroupId, action, message); //commenting for speed test
|
|
return new OkObjectResult(fr);
|
|
}
|
|
|
|
internal static async Task<IActionResult> AddFileUserInternal(AddFileUserDto dto)
|
|
{
|
|
// check to see if the email has the power to add a user
|
|
string userId = Helpers.HashAndShortenText(dto.Email.ToLower());
|
|
|
|
FileRecord fr = await CDPDB.GetFile(dto.AppKey, dto.FileId, userId);
|
|
if (fr == null)
|
|
{
|
|
string message = string.Format($"{dto.Email} attempted to add/change access policy for {dto.EmailToAdd} on {dto.FileName} file having {dto.FileId} id, but didn't have ANY access");
|
|
Console.WriteLine(message);
|
|
string action = "Policy change failed";
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, dto.FileId, dto.FileName, userId, "", action, message);
|
|
|
|
return new BadRequestObjectResult(new { error = true, message = "File not found for user " + dto.Email });
|
|
}
|
|
|
|
if ((!fr.Policy.CheckAccess("Manage")) && (!fr.Policy.CheckAccess("Owner")))
|
|
{
|
|
string message = string.Format($"{dto.Email} attempted to add/change access policy for {dto.EmailToAdd} on {dto.FileName} file having {dto.FileId} id, but didn't have manage access");
|
|
Console.WriteLine(message);
|
|
string action = "Policy change failed";
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, dto.FileId, dto.FileName, userId, "", action, message);
|
|
return new BadRequestObjectResult(new { error = true, message = $"{dto.Email} doesn't have the rights to add a user." });
|
|
}
|
|
|
|
string fileId = dto.FileId;
|
|
string fileName = dto.FileName;
|
|
string userIdToAdd = "";
|
|
|
|
if (dto.EmailToAdd != "")
|
|
{
|
|
userIdToAdd = Helpers.HashAndShortenText(dto.EmailToAdd.ToLower());
|
|
}
|
|
else if (dto.Group != null)
|
|
{
|
|
userIdToAdd = dto.GroupId;
|
|
}
|
|
else if (dto.Group != null)
|
|
{
|
|
userIdToAdd = dto.GroupId;
|
|
}
|
|
|
|
AccessPolicy ac = new AccessPolicy()
|
|
{
|
|
Access = dto.Policy,
|
|
Email = dto.EmailToAdd.ToLower(),
|
|
Group = dto.Group,
|
|
GroupId = dto.GroupId,
|
|
Key = ""
|
|
};
|
|
|
|
fr = await CDPDB.UpsertFile(dto.AppKey, fileId, fileName, userIdToAdd, "", ac);
|
|
|
|
if (dto.EmailToAdd != "")
|
|
{
|
|
string message = string.Format($"{dto.Email} added/changed the access policy for User : {dto.EmailToAdd} to {dto.Policy} on {fileName} file having {fileId} id");
|
|
string action = "Policy change";
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, fileId, fileName, userId, "", action, message);
|
|
}
|
|
|
|
if (dto.Group != null)
|
|
{
|
|
string message = string.Format($"{dto.Email} added/changed the access policy for Group : {dto.Group} to {dto.Policy} on {fileName} file having {fileId} id");
|
|
string action = "Policy change";
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, fileId, fileName, "", dto.Group.id, action, message);
|
|
}
|
|
return new OkObjectResult(fr);
|
|
}
|
|
|
|
#region CDP File Functions
|
|
|
|
[Function("AddFile")]
|
|
public async Task<IActionResult> AddFile([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
|
|
{
|
|
_logger.LogInformation("AddFile invoked");
|
|
|
|
// Convert the JSON payload to a string
|
|
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
|
|
AddFileDto dto = JsonConvert.DeserializeObject<AddFileDto>(requestBody);
|
|
if (dto == null)
|
|
return new BadRequestObjectResult(new { error = true, message = "Parse error." });
|
|
|
|
return await AddFileInternal(dto, true);
|
|
}
|
|
|
|
[Function("AddFileUser")]
|
|
public async Task<IActionResult> AddFileUser([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
|
|
{
|
|
_logger.LogInformation("AddFileUser invoked");
|
|
|
|
// Convert the JSON payload to a string
|
|
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
|
|
AddFileUserDto dto = JsonConvert.DeserializeObject<AddFileUserDto>(requestBody);
|
|
if (dto == null)
|
|
return new BadRequestObjectResult(new { error = true, message = "Parse error." });
|
|
|
|
return await AddFileUserInternal(dto);
|
|
}
|
|
|
|
[Function("GetFileForUser")]
|
|
public async Task<IActionResult> GetFileForUser([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
|
|
{
|
|
_logger.LogInformation("GetFile invoked");
|
|
|
|
// Convert the JSON payload to a string
|
|
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
|
|
AddFileUserDto dto = JsonConvert.DeserializeObject<AddFileUserDto>(requestBody);
|
|
if (dto == null)
|
|
return new BadRequestObjectResult(new { error = true, message = "Parse error." });
|
|
|
|
// check to see if the email has the power to add a user
|
|
// string a = Helpers.HashAndShortenText(dto.Email.ToLower());
|
|
// string b = Helpers.HashToHex(dto.Email.ToLower());
|
|
// string c = Helpers.ConvertShortHashToHex(a);
|
|
|
|
string userId = Helpers.HashAndShortenText(dto.Email.ToLower());
|
|
// userId = "user-" + Helpers.HashToHex(dto.Email.ToLower());
|
|
|
|
FileRecord fr = await CDPDB.GetFile(dto.AppKey, dto.FileId, userId);
|
|
if (fr == null)
|
|
{
|
|
string AuditMessage = string.Format($"File not found for user {dto.Email} having fileId {dto.FileId}");
|
|
string AuditAction = "Decrypt failed";
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, dto.FileId, dto.FileName, userId, "", AuditAction, AuditMessage);
|
|
return new BadRequestObjectResult(new { error = true, message = "File not found for user " + dto.Email });
|
|
}
|
|
|
|
if (fr.Policy.CheckAccess("None"))
|
|
{
|
|
string AuditMessage = string.Format($"{dto.Email} don't have the rights to decrypt {fr.FileName} file having {dto.FileId} id");
|
|
string AuditAction = "Decrypt failed";
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, dto.FileId, fr.FileName, userId, "", AuditAction, AuditMessage);
|
|
return new BadRequestObjectResult(new { error = true, message = "Access is denied for user " + dto.Email });
|
|
}
|
|
|
|
KeyVaultService kvs = new KeyVaultService(Constants.KeyVaultURI);
|
|
fr.Policy.Key = await kvs.GetSecretAsync(fr.FileId);
|
|
|
|
string message = string.Format($"{dto.Email} decrypted {fr.FileName} file having {dto.FileId} id");
|
|
string action = "Decrypted";
|
|
await AuditFunctions.AddAuditsEvent(dto.AppKey, dto.FileId, dto.FileName, userId, "", action, message);
|
|
|
|
return new OkObjectResult(fr);
|
|
}
|
|
|
|
[Function("GetPoliciesForFile")]
|
|
public async Task<IActionResult> GetPoliciesForFile([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
|
|
{
|
|
_logger.LogInformation("GetFile invoked");
|
|
|
|
// Convert the JSON payload to a string
|
|
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
|
|
GetPoliciesForFileDto dto = JsonConvert.DeserializeObject<GetPoliciesForFileDto>(requestBody);
|
|
if (dto == null)
|
|
return new BadRequestObjectResult(new { error = true, message = "Parse error." });
|
|
|
|
List<FileRecord> fr = await CDPDB.GetPoliciesForFile(dto.AppKey, dto.FileId);
|
|
if (fr == null)
|
|
{
|
|
return new BadRequestObjectResult(new { error = true, message = "File not found " + dto.FileId });
|
|
}
|
|
KeyVaultService kvs = new KeyVaultService(Constants.KeyVaultURI);
|
|
string aesKey = await kvs.GetSecretAsync(dto.FileId);
|
|
foreach (var f in fr)
|
|
{
|
|
f.Policy.Key = aesKey;
|
|
}
|
|
|
|
return new OkObjectResult(fr);
|
|
}
|
|
|
|
[Function("DeleteRegisteredUserPolicies")]
|
|
public async Task<IActionResult> DeleteRegisteredUserPolicies([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
|
|
{
|
|
_logger.LogInformation("Deleting Registered User invoked");
|
|
|
|
// Convert the JSON payload to a string
|
|
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
|
|
DeleteRegisteredUserDto deleteContactdto = JsonConvert.DeserializeObject<DeleteRegisteredUserDto>(requestBody);
|
|
if (deleteContactdto == null)
|
|
return new BadRequestObjectResult(new { error = true, message = "Parse error." });
|
|
|
|
string userId = Helpers.HashAndShortenText(deleteContactdto.UserEmail.ToLower());
|
|
await CDPDB.revokeRegisteredUserPolicies(deleteContactdto.AppKey, deleteContactdto.UserEmail.ToLower(), deleteContactdto.ContactEmail.ToLower(), deleteContactdto.AdminEmail.ToLower());
|
|
|
|
return new OkObjectResult(true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Background Processing Support
|
|
|
|
public static async Task<Job> AddAuditsBatchedEvent(List<AuditEventMetadata> auditEvents, string appKey)
|
|
{
|
|
using (var mt = new MethodTimer("AddAuditsBatchedEvent"))
|
|
{
|
|
string jobMeta = JsonConvert.SerializeObject(auditEvents);
|
|
string jobId = Guid.NewGuid().ToString();
|
|
Job job = new Job { AppKey = appKey, EventType = JobType.AddAuditsBatch, Id = jobId, JobMetadata = jobMeta };
|
|
return job;
|
|
}
|
|
}
|
|
|
|
public static async Task<Job> AddKeyVaultBatchedEvent(List<KeyVaultEvent> vaultEvents, string appKey)
|
|
{
|
|
using (var mt = new MethodTimer("AddKeyVaultBatchedEvent"))
|
|
{
|
|
string jobMeta = JsonConvert.SerializeObject(vaultEvents);
|
|
string jobId = Guid.NewGuid().ToString();
|
|
Job job = new Job { AppKey = appKey, EventType = JobType.KeyVaultInsertionBatch, Id = jobId, JobMetadata = jobMeta };
|
|
//await MetaProcessor.PublishJob(job);
|
|
return job;
|
|
}
|
|
}
|
|
|
|
public static async Task<string> AddKeyVaultEvent(string fileId, string aesKey, string appKey)
|
|
{
|
|
using (var mt = new MethodTimer("AddKeyVaultEvent"))
|
|
{
|
|
KeyVaultEvent vaultEvent = new KeyVaultEvent { AESKey = aesKey, FileId = fileId };
|
|
string jobMeta = JsonConvert.SerializeObject(vaultEvent);
|
|
string jobId = Guid.NewGuid().ToString();
|
|
Job keyVaultJob = new Job { AppKey = appKey, EventType = JobType.KeyVaultInsertion, Id = jobId, JobMetadata = jobMeta };
|
|
await MetaProcessor.PublishJob(keyVaultJob);
|
|
return jobId;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|