diff --git a/src/Plugins/AWSS3/StorageAdminService.cs b/src/Plugins/AWSS3/StorageAdminService.cs index 41f2ab0..c21c27e 100644 --- a/src/Plugins/AWSS3/StorageAdminService.cs +++ b/src/Plugins/AWSS3/StorageAdminService.cs @@ -26,5 +26,6 @@ public class StorageAdminService : IStorageAdminService { public Task CreateUserAsync(string username, AccessPermissions permissions, string[] bucketNames) => throw new NotImplementedException(); public Task CreateUserAsync(string username, PolicyRequest[] policyRequests) => throw new NotImplementedException(); + public Task RemoveUserAsync(string username) => throw new NotImplementedException(); } } diff --git a/src/Plugins/MinIO/StorageAdminService.cs b/src/Plugins/MinIO/StorageAdminService.cs index 55ce093..ab68fb6 100644 --- a/src/Plugins/MinIO/StorageAdminService.cs +++ b/src/Plugins/MinIO/StorageAdminService.cs @@ -73,10 +73,20 @@ private static void ValidateConfiguration(StorageServiceConfiguration configurat } } - private string CreateUserCmd(string username, string secretKey) => $"admin user add {_serviceName} {username} {secretKey}"; + private string CreateUserCmd(string username, string secretKey) + { + Guard.Against.NullOrWhiteSpace(username, nameof(username)); + Guard.Against.NullOrWhiteSpace(secretKey, nameof(secretKey)); + + return $"admin user add {_serviceName} {username} {secretKey}"; + } public async Task SetPolicyAsync(IdentityType policyType, List policies, string itemName) { + Guard.Against.Null(policyType, nameof(policyType)); + Guard.Against.Null(policies, nameof(policies)); + Guard.Against.NullOrWhiteSpace(itemName, nameof(itemName)); + var policiesStr = string.Join(',', policies); var setPolicyCmd = $"admin policy set {_serviceName} {policiesStr} {policyType.ToString().ToLower()}={itemName}"; var result = await ExecuteAsync(setPolicyCmd).ConfigureAwait(false); @@ -91,6 +101,8 @@ public async Task SetPolicyAsync(IdentityType policyType, List pol private async Task> ExecuteAsync(string cmd) { + Guard.Against.NullOrWhiteSpace(cmd, nameof(cmd)); + if (cmd.StartsWith("mc")) { throw new InvalidOperationException($"Incorrect command \"{cmd}\""); @@ -110,6 +122,8 @@ private async Task> ExecuteAsync(string cmd) private static async Task<(List Output, List Errors)> RunProcessAsync(Process process) { + Guard.Against.Null(process, nameof(process)); + var output = new List(); var errors = new List(); process.Start(); @@ -132,6 +146,8 @@ private async Task> ExecuteAsync(string cmd) private Process CreateProcess(string cmd) { + Guard.Against.NullOrWhiteSpace(cmd, nameof(cmd)); + ProcessStartInfo startinfo = new() { FileName = _executableLocation, @@ -172,12 +188,16 @@ public async Task SetConnectionAsync() public async Task UserAlreadyExistsAsync(string username) { + Guard.Against.NullOrWhiteSpace(username, nameof(username)); + var result = await ExecuteAsync(_get_users_cmd).ConfigureAwait(false); return result.Any(r => r.Contains(username)); } public async Task RemoveUserAsync(string username) { + Guard.Against.NullOrWhiteSpace(username, nameof(username)); + var result = await ExecuteAsync($"admin user remove {_serviceName} {username}").ConfigureAwait(false); if (!result.Any(r => r.Contains($"Removed user `{username}` successfully."))) @@ -189,6 +209,9 @@ public async Task RemoveUserAsync(string username) [Obsolete("CreateUserAsync with bucketNames is deprecated, please use CreateUserAsync with an array of PolicyRequest instead.")] public async Task CreateUserAsync(string username, AccessPermissions permissions, string[] bucketNames) { + Guard.Against.NullOrWhiteSpace(username, nameof(username)); + Guard.Against.Null(bucketNames, nameof(bucketNames)); + var policyRequests = new List(); for (var i = 0; i < bucketNames.Length; i++) @@ -201,6 +224,9 @@ public async Task CreateUserAsync(string username, AccessPermission public async Task CreateUserAsync(string username, PolicyRequest[] policyRequests) { + Guard.Against.NullOrWhiteSpace(username, nameof(username)); + Guard.Against.Null(policyRequests, nameof(policyRequests)); + if (!await SetConnectionAsync()) { throw new InvalidOperationException("Unable to set connection for more information, attempt mc alias set {_serviceName} http://{_endpoint} {_accessKey} {_secretKey}"); @@ -247,6 +273,9 @@ public async Task CreateUserAsync(string username, PolicyRequest[] /// private async Task CreatePolicyAsync(PolicyRequest[] policyRequests, string username) { + Guard.Against.Null(policyRequests, nameof(policyRequests)); + Guard.Against.NullOrWhiteSpace(username, nameof(username)); + var policyFileName = await CreatePolicyFile(policyRequests, username).ConfigureAwait(false); var result = await ExecuteAsync($"admin policy add {_serviceName} pol_{username} {policyFileName}").ConfigureAwait(false); if (result.Any(r => r.Contains($"Added policy `pol_{username}` successfully.")) is false) diff --git a/src/S3Policy/PolicyExtensions.cs b/src/S3Policy/PolicyExtensions.cs index 9912ae4..296858a 100644 --- a/src/S3Policy/PolicyExtensions.cs +++ b/src/S3Policy/PolicyExtensions.cs @@ -99,19 +99,19 @@ public static Policy ToPolicy(PolicyRequest[] policyRequests) Sid = "AllowUserToSeeBucketListInTheConsole", Action = new string[] {"s3:ListAllMyBuckets", "s3:GetBucketLocation" }, Effect = "Allow", - Resource = policyRequests.Select(pr => pr.BucketName).ToArray(), + Resource = policyRequests.Select(pr => pr.BucketName).Distinct().ToArray(), }, new Statement { Sid = "AllowRootAndHomeListingOfBucket", Action = new string[] { "s3:ListBucket" }, Effect = "Allow", - Resource = policyRequests.Select(pr => pr.BucketName).ToArray(), + Resource = policyRequests.Select(pr => pr.BucketName).Distinct().ToArray(), Condition = new Condition { StringEquals = new StringEquals { - S3Prefix = pathList.ToArray(), + S3Prefix = pathList.Distinct().ToArray(), S3Delimiter = new string[] { "/" } } } @@ -121,13 +121,15 @@ public static Policy ToPolicy(PolicyRequest[] policyRequests) Sid = "AllowListingOfUserFolder", Action = new string[] { "s3:ListBucket" }, Effect = "Allow", - Resource = policyRequests.Select(pr => pr.BucketName).ToArray(), + Resource = policyRequests.Select(pr => pr.BucketName).Distinct().ToArray(), Condition = new Condition { StringLike = new StringLike { - S3Prefix = policyRequests.Select(pr => $"{pr.FolderName}/*") - .Union( policyRequests.Select(pr => $"{pr.FolderName}")).ToArray() + S3Prefix = policyRequests + .Select(pr => $"{pr.FolderName}/*") + .Union( policyRequests.Select(pr => $"{pr.FolderName}")) + .Distinct().ToArray() } } }, @@ -136,7 +138,10 @@ public static Policy ToPolicy(PolicyRequest[] policyRequests) Sid = "AllowAllS3ActionsInUserFolder", Action = new string[] { "s3:*" }, Effect = "Allow", - Resource = policyRequests.Select(pr => $"{pr.BucketName}/{pr.FolderName}/*").ToArray(), + Resource = policyRequests + .Select(pr => System.IO.Path.Join(pr.BucketName, pr.FolderName, "*")) + .Distinct() + .ToArray(), }, } }; diff --git a/src/Storage/API/IStorageAdminService.cs b/src/Storage/API/IStorageAdminService.cs index eca09bf..b9ab702 100644 --- a/src/Storage/API/IStorageAdminService.cs +++ b/src/Storage/API/IStorageAdminService.cs @@ -38,5 +38,11 @@ public interface IStorageAdminService /// Contains the buckets and folders that the user needs access to /// Task CreateUserAsync(string username, PolicyRequest[] policyRequests); + + /// + /// Removes a user account + /// + /// Username + Task RemoveUserAsync(string username); } }