Temporary repo to track my changes on LTS functions app porting
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

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
}
}