private void AdjustVMForAuthorization(AuthorizeApiKeysViewModel vm) { var parsedPermissions = Permission.ToPermissions(vm.Permissions.Split(';')).GroupBy(permission => permission.Policy); for (var index = vm.PermissionValues.Count - 1; index >= 0; index--) { var permissionValue = vm.PermissionValues[index]; var wanted = parsedPermissions?.SingleOrDefault(permission => permission.Key.Equals(permissionValue.Permission, StringComparison.InvariantCultureIgnoreCase)); if (vm.Strict && !(wanted?.Any() ?? false)) { vm.PermissionValues.RemoveAt(index); continue; } else if (wanted?.Any() ?? false) { if (vm.SelectiveStores && Policies.IsStorePolicy(permissionValue.Permission) && wanted.Any(permission => !string.IsNullOrEmpty(permission.StoreId))) { permissionValue.StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.Specific; permissionValue.SpecificStores = wanted.Select(permission => permission.StoreId).ToList(); } else { permissionValue.StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.AllStores; permissionValue.SpecificStores = new List <string>(); permissionValue.Value = true; } } } }
public async Task <IActionResult> AuthorizeAPIKey([FromForm] AuthorizeApiKeysViewModel viewModel) { await SetViewModelValues(viewModel); AdjustVMForAuthorization(viewModel); var ar = HandleCommands(viewModel); if (ar != null) { return(ar); } for (int i = 0; i < viewModel.PermissionValues.Count; i++) { if (viewModel.PermissionValues[i].Forbidden && viewModel.Strict) { viewModel.PermissionValues[i].Value = false; ModelState.AddModelError($"{viewModel.PermissionValues}[{i}].Value", $"The permission '{viewModel.PermissionValues[i].Title}' is required for this application."); } if (viewModel.PermissionValues[i].StoreMode == AddApiKeyViewModel.ApiKeyStoreMode.Specific && !viewModel.SelectiveStores) { viewModel.PermissionValues[i].StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.AllStores; ModelState.AddModelError($"{viewModel.PermissionValues}[{i}].Value", $"The permission '{viewModel.PermissionValues[i].Title}' cannot be store specific for this application."); } } if (!ModelState.IsValid) { return(View(viewModel)); } switch (viewModel.Command.ToLowerInvariant()) { case "no": return(RedirectToAction("APIKeys")); case "yes": var key = await CreateKey(viewModel, (viewModel.ApplicationIdentifier, viewModel.RedirectUrl?.Authority)); if (viewModel.RedirectUrl != null) { return(Redirect(GetRedirectToApplicationUrl(viewModel.RedirectUrl, key))); } TempData.SetStatusMessageModel(new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Success, Html = $"API key generated! <code class='alert-link'>{key.Id}</code>" }); return(RedirectToAction("APIKeys", new { key = key.Id })); default: return(View(viewModel)); } }
public async Task <IActionResult> AuthorizeAPIKey(string[] permissions, string applicationName = null, Uri redirect = null, bool strict = true, bool selectiveStores = false, string applicationIdentifier = null) { if (!_btcPayServerEnvironment.IsSecure) { TempData.SetStatusMessageModel(new StatusMessageModel { Severity = StatusMessageModel.StatusSeverity.Error, Message = "Cannot generate API keys while not on https or using Tor" }); return(RedirectToAction("APIKeys")); } permissions ??= Array.Empty <string>(); var requestPermissions = Permission.ToPermissions(permissions).ToList(); if (redirect?.IsAbsoluteUri is false) { redirect = null; } var vm = new AuthorizeApiKeysViewModel { RedirectUrl = redirect, Label = applicationName, ApplicationName = applicationName, SelectiveStores = selectiveStores, Strict = strict, Permissions = string.Join(';', requestPermissions), ApplicationIdentifier = applicationIdentifier }; var existingApiKey = await CheckForMatchingApiKey(requestPermissions, vm); if (existingApiKey != null) { vm.ApiKey = existingApiKey.Id; return(View("ConfirmAPIKey", vm)); } vm = await SetViewModelValues(vm); AdjustVMForAuthorization(vm); return(View(vm)); }
public async Task <IActionResult> AuthorizeAPIKey([FromForm] AuthorizeApiKeysViewModel viewModel) { await SetViewModelValues(viewModel); AdjustVMForAuthorization(viewModel); var ar = HandleCommands(viewModel); if (ar != null) { return(ar); } for (int i = 0; i < viewModel.PermissionValues.Count; i++) { if (viewModel.PermissionValues[i].Forbidden && viewModel.Strict) { viewModel.PermissionValues[i].Value = false; ModelState.AddModelError($"{viewModel.PermissionValues}[{i}].Value", $"The permission '{viewModel.PermissionValues[i].Title}' is required for this application."); } if (viewModel.PermissionValues[i].StoreMode == AddApiKeyViewModel.ApiKeyStoreMode.Specific && !viewModel.SelectiveStores) { viewModel.PermissionValues[i].StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.AllStores; ModelState.AddModelError($"{viewModel.PermissionValues}[{i}].Value", $"The permission '{viewModel.PermissionValues[i].Title}' cannot be store specific for this application."); } } if (!ModelState.IsValid) { return(View(viewModel)); } var command = viewModel.Command.ToLowerInvariant(); switch (command) { case "cancel": return(RedirectToAction("APIKeys")); case "authorize": case "confirm": var key = command == "authorize" ? await CreateKey(viewModel, (viewModel.ApplicationIdentifier, viewModel.RedirectUrl?.Authority)) : await _apiKeyRepository.GetKey(viewModel.ApiKey); if (viewModel.RedirectUrl != null) { var permissions = key.GetBlob().Permissions; var redirectVm = new PostRedirectViewModel() { FormUrl = viewModel.RedirectUrl.ToString(), Parameters = { new KeyValuePair <string, string>("apiKey", key.Id), new KeyValuePair <string, string>("userId", key.UserId) } }; foreach (var permission in permissions) { redirectVm.Parameters.Add( new KeyValuePair <string, string>("permissions[]", permission)); } return(View("PostRedirect", redirectVm)); } TempData.SetStatusMessageModel(new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Success, Html = $"API key generated! <code class='alert-link'>{key.Id}</code>" }); return(RedirectToAction("APIKeys", new { key = key.Id })); default: return(View(viewModel)); } }
private void AdjustVMForAuthorization(AuthorizeApiKeysViewModel vm) { var permissions = vm.Permissions?.Split(';') ?? Array.Empty <string>(); var permissionsWithStoreIDs = new List <string>(); /** * Go over each permission and associated store IDs and * join them so that permission for a specific store is parsed correctly */ for (var i = 0; i < permissions.Length; i++) { var currPerm = permissions[i]; var storeIds = vm.PermissionValues[i].SpecificStores.ToArray(); if (storeIds.Length > 0) { for (var x = 0; x < storeIds.Length; x++) { permissionsWithStoreIDs.Add($"{currPerm}:{storeIds[x]}"); } } else { permissionsWithStoreIDs.Add(currPerm); } } var parsedPermissions = Permission.ToPermissions(permissionsWithStoreIDs.ToArray()).GroupBy(permission => permission.Policy); for (var index = vm.PermissionValues.Count - 1; index >= 0; index--) { var permissionValue = vm.PermissionValues[index]; var wanted = parsedPermissions?.SingleOrDefault(permission => permission.Key.Equals(permissionValue.Permission, StringComparison.InvariantCultureIgnoreCase)); if (vm.Strict && !(wanted?.Any() ?? false)) { vm.PermissionValues.RemoveAt(index); continue; } else if (wanted?.Any() ?? false) { var commandParts = vm.Command?.Split(':', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty <string>(); var command = commandParts.Length > 1 ? commandParts[1] : null; var isPerformingAnAction = command == "change-store-mode" || command == "add-store"; // Don't want to accidentally change mode for the user if they are explicitly performing some action if (isPerformingAnAction) { continue; } if (vm.SelectiveStores && Policies.IsStorePolicy(permissionValue.Permission) && wanted.Any(permission => !string.IsNullOrEmpty(permission.Scope))) { permissionValue.StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.Specific; permissionValue.SpecificStores = wanted.Select(permission => permission.Scope).ToList(); } else { permissionValue.StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.AllStores; permissionValue.SpecificStores = new List <string>(); permissionValue.Value = true; } } } }
public async Task <IActionResult> AuthorizeAPIKey([FromForm] AuthorizeApiKeysViewModel viewModel) { await SetViewModelValues(viewModel); var ar = HandleCommands(viewModel); if (ar != null) { return(ar); } if (viewModel.PermissionsFormatted.Contains(Permissions.ServerManagement)) { if (!viewModel.IsServerAdmin && viewModel.ServerManagementPermission) { viewModel.ServerManagementPermission = false; } if (!viewModel.ServerManagementPermission && viewModel.Strict) { ModelState.AddModelError(nameof(viewModel.ServerManagementPermission), "This permission is required for this application."); } } if (viewModel.PermissionsFormatted.Contains(Permissions.StoreManagement)) { if (!viewModel.SelectiveStores && viewModel.StoreMode == AddApiKeyViewModel.ApiKeyStoreMode.Specific) { viewModel.StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.AllStores; ModelState.AddModelError(nameof(viewModel.StoreManagementPermission), "This application does not allow selective store permissions."); } if (!viewModel.StoreManagementPermission && !viewModel.SpecificStores.Any() && viewModel.Strict) { ModelState.AddModelError(nameof(viewModel.StoreManagementPermission), "This permission is required for this application."); } } if (!ModelState.IsValid) { return(View(viewModel)); } switch (viewModel.Command.ToLowerInvariant()) { case "no": return(RedirectToAction("APIKeys")); case "yes": var key = await CreateKey(viewModel); TempData.SetStatusMessageModel(new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Success, Html = $"API key generated! <code>{key.Id}</code>" }); return(RedirectToAction("APIKeys", new { key = key.Id })); default: return(View(viewModel)); } }
private async Task <APIKeyData> CheckForMatchingApiKey(IEnumerable <Permission> requestedPermissions, AuthorizeApiKeysViewModel vm) { if (string.IsNullOrEmpty(vm.ApplicationIdentifier) || vm.RedirectUrl == null) { return(null); } //check if there is an app identifier that matches and belongs to the current user var keys = await _apiKeyRepository.GetKeys(new APIKeyRepository.APIKeyQuery { UserId = new[] { _userManager.GetUserId(User) } }); foreach (var key in keys) { var blob = key.GetBlob(); if (blob.ApplicationIdentifier != vm.ApplicationIdentifier || blob.ApplicationAuthority != vm.RedirectUrl.AbsoluteUri) { continue; } var requestedGrouped = requestedPermissions.GroupBy(permission => permission.Policy); var existingGrouped = Permission.ToPermissions(blob.Permissions).GroupBy(permission => permission.Policy); //matched the identifier and authority, but we need to check if what the app is requesting in terms of permissions is enough var fail = false; foreach (var requested in requestedGrouped) { var existing = existingGrouped.SingleOrDefault(grouping => requested.Key == grouping.Key); if (vm.Strict && existing == null) { fail = true; break; } if (Policies.IsStorePolicy(requested.Key)) { if ((vm.SelectiveStores && !existing.Any(p => p.Scope == vm.StoreId)) || (!vm.SelectiveStores && existing.Any(p => !string.IsNullOrEmpty(p.Scope)))) { fail = true; break; } } } if (fail) { continue; } //we have a key that is sufficient, redirect to a page to confirm that it's ok to provide this key to the app. return(key); } return(null); }
public async Task <IActionResult> AuthorizeAPIKey([FromForm] AuthorizeApiKeysViewModel viewModel) { await SetViewModelValues(viewModel); var ar = HandleCommands(viewModel); if (ar != null) { return(ar); } if (viewModel.Strict) { for (int i = 0; i < viewModel.PermissionValues.Count; i++) { if (viewModel.PermissionValues[i].Forbidden) { ModelState.AddModelError($"{viewModel.PermissionValues}[{i}].Value", $"The permission '{viewModel.PermissionValues[i].Title}' is required for this application."); } } } var permissions = Permission.ToPermissions(viewModel.Permissions).ToHashSet(); if (permissions.Contains(Permission.Create(Policies.CanModifyStoreSettings))) { if (!viewModel.SelectiveStores && viewModel.StoreMode == AddApiKeyViewModel.ApiKeyStoreMode.Specific) { viewModel.StoreMode = AddApiKeyViewModel.ApiKeyStoreMode.AllStores; ModelState.AddModelError(nameof(viewModel.StoreManagementPermission), "This application does not allow selective store permissions."); } if (!viewModel.StoreManagementPermission.Value && !viewModel.SpecificStores.Any() && viewModel.Strict) { ModelState.AddModelError(nameof(viewModel.StoreManagementPermission), $"This permission '{viewModel.StoreManagementPermission.Title}' is required for this application."); } } if (!ModelState.IsValid) { return(View(viewModel)); } switch (viewModel.Command.ToLowerInvariant()) { case "no": return(RedirectToAction("APIKeys")); case "yes": var key = await CreateKey(viewModel); TempData.SetStatusMessageModel(new StatusMessageModel() { Severity = StatusMessageModel.StatusSeverity.Success, Html = $"API key generated! <code>{key.Id}</code>" }); return(RedirectToAction("APIKeys", new { key = key.Id })); default: return(View(viewModel)); } }