/// <summary> /// Returns a Token object of the Token that is currently being used to access Vault with. This routine also exists within the VaultAuthentication Backend. /// </summary> /// <remarks>This routine and the one in VaultAuthenticationBackend should be kept in sync.</remarks> /// <returns>Token object of the current token used to access Vault Instance with.</returns> public async Task <Token> GetMyTokenInfo() { string path = "/v1/auth/token/lookup-self"; try { VaultDataResponseObjectB vdro = await ParentVault._httpConnector.GetAsync_B(path, "GetMyTokenInfo"); if (vdro.Success) { return(await vdro.GetDotNetObject <Token>()); } else { throw new VaultUnexpectedCodePathException(); } } // If Vault is telling us it is a bad token, then return null. catch (VaultForbiddenException e) { if (e.Message.Contains("bad token")) { return(null); } else { throw e; } } }
/// <summary> /// Calls the HTTP Post method, to send data to the Vault API server. /// This is the updated version. /// </summary> /// <param name="APIPath">The path to call on the Vault server.</param> /// <param name="callingRoutineName">String name of the routine that called this method. Used for debugging and logging purposes only.</param> /// <param name="inputParamsJSON">JSON string of the parameters you want to put in the body of the HTTP call. This is used to override the inputParams Dictionary.</param> /// <param name="expectReturnToHaveBody">Set to true to optimize the call by not retrieving the body from the response because it is not needed or expected to be empty.</param> /// <returns>VaultDataResponseObject with the results of the call.</returns> public async Task <VaultDataResponseObjectB> PostAsync_B(string APIPath, string callingRoutineName, string inputParamsJSON = "", bool expectReturnToHaveBody = true) { HttpContent contentBody = new StringContent(inputParamsJSON); contentBody.Headers.ContentType = new MediaTypeHeaderValue("application/json"); HttpResponseMessage response = await _httpClt.PostAsync(APIPath, contentBody); if (response.IsSuccessStatusCode) { VaultDataResponseObjectB vdr; if (!expectReturnToHaveBody) { vdr = new VaultDataResponseObjectB(response.StatusCode); } else { vdr = new VaultDataResponseObjectB(response); } return(vdr); } else { // Process errors. This method will always throw an error. await HandleVaultErrors(response, APIPath, callingRoutineName); return(null); } }
/// <summary> /// Calls the HTTP PUT method, to send data to the Vault API server. /// </summary> /// <param name="APIPath">The path to call on the Vault server.</param> /// <param name="callingRoutineName">String name of the routine that called this method. Used for debugging and logging purposes only.</param> /// <param name="inputParams">A Dictionary of key value pairs of parameters that should be sent in the body of the HTTP Call. Should set to null if overriding /// with your own JSON string of parameters by setting the inputParamsJSON</param> /// <param name="inputParamsJSON">JSON string of the parameters you want to put in the body of the HTTP call. This is used to override the inputParams Dictionary.</param> /// <returns>VaultDataResponseObject with the results of the call.</returns> public async Task <VaultDataResponseObjectB> PutAsync(string APIPath, string callingRoutineName, Dictionary <string, string> inputParams = null, string inputParamsJSON = "") { if (inputParams != null) { inputParamsJSON = JsonConvert.SerializeObject(inputParams, Formatting.None); } HttpContent contentBody = new StringContent(inputParamsJSON); contentBody.Headers.ContentType = new MediaTypeHeaderValue("application/json"); string jsonResponse = ""; HttpResponseMessage response = await _httpClt.PutAsync(APIPath, contentBody); if (response.IsSuccessStatusCode) { jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } else { await HandleVaultErrors(response, APIPath, callingRoutineName); } VaultDataResponseObjectB vdr = new VaultDataResponseObjectB(response); return(vdr); }
/// <summary> /// Attempts to read the sys mount config to determine if the path exists or not. Returns true if the path exists, false otherwise /// </summary> /// <param name="mountPath">The name (path) of the backend to verify the existence of</param> /// <returns></returns> public async Task <bool> SysMountExists(string mountPath) { // Build Path string path = MountPointPath + pathMounts + mountPath + "/tune"; try { VaultDataResponseObjectB vdro = await ParentVault._httpConnector.GetAsync_B(path, "SysMountReadConfig", null); if (vdro.Success) { return(true); } } catch (VaultInvalidDataException ve) { if (ve.Message.Contains("cannot fetch sysview for path")) { return(false); } throw ve; } return(false); }
/// <summary> /// Returns a Dictionary of objects and the permissions they contains, as well as an overall Capabilities object that summarizes the /// permissions that a Token has on the List of paths provided. /// <para>https://www.vaultproject.io/api/system/capabilities.html</para> /// </summary> /// <param name="tokenID">The Token to evaluate</param> /// <param name="paths">A list of paths to check the token against</param> /// <returns></returns> public async Task <Dictionary <string, List <string> > > GetTokenCapabilityOnPaths(string tokenID, List <string> paths) { string path = MountPointPath + "capabilities"; // Add the token and paths parameters Dictionary <string, object> contentParams = new Dictionary <string, object>() { { "token", tokenID }, { "paths", paths } }; try { VaultDataResponseObjectB vdro = await ParentVault._httpConnector.PostAsync_B(path, "GetTokenCapabilityOnPaths", contentParams); if (vdro.Success) { Dictionary <string, List <string> > capabilities = await vdro.GetDotNetObject <Dictionary <string, List <string> > >(); return(capabilities); } throw new ApplicationException("IdentitySecretEngine:ListEntitiesByName -> Arrived at unexpected code block."); } // 404 Errors mean there were no entities. We just return an empty list. catch (VaultInvalidPathException) { return(null); } }
/// <summary> /// Enables the provided Authentication backend. /// </summary> /// <param name="am">The AuthMethod object that represents the authentication engine to enable.</param> /// <returns>True if authentication engine was successfully enabled. False otherwise. /// Throws exception: VaultException with SpecificErrorCode set to BackendMountAlreadyExists if a mount already exists at that location. /// </returns> public async Task <bool> AuthEnable(AuthMethod am) { string path = MountPointPath + "auth/" + am.Name; Dictionary <string, string> contentParams = new Dictionary <string, string>(); contentParams.Add("path", am.Path); contentParams.Add("description", am.Description); contentParams.Add("type", am.TypeAsString); string contentJSON = JsonConvert.SerializeObject(contentParams, Formatting.None); StringBuilder jsonConfig; string json = ""; if (am.Config != null) { jsonConfig = new StringBuilder(JsonConvert.SerializeObject(am.Config)); jsonConfig.Insert(0, "\"config\":"); // Combine the 2 JSON's, by stripping trailing closing brace from the content param JSON string. StringBuilder jsonParams = new StringBuilder(contentJSON, (contentJSON.Length + jsonConfig.Length + 20)); jsonParams.Remove(jsonParams.Length - 1, 1); jsonParams.Append(","); // Remove the opening brace. jsonParams.Append(jsonConfig); jsonParams.Append("}"); json = jsonParams.ToString(); } else { json = contentJSON; } try { VaultDataResponseObjectB vdro = await ParentVault._httpConnector.PostAsync_B(path, "VaultSystemBackend:AuthEnable", json, false); return(vdro.Success); } catch (VaultInvalidDataException e) { if (e.Message.Contains("path is already in use")) { VaultException ex = new VaultException("The authentication backend mount point already exists. Cannot enable another mount point at that location."); ex.SpecificErrorCode = EnumVaultExceptionCodes.BackendMountAlreadyExists; throw ex; } else { throw e; } } }
/// <summary> /// Deletes the backend Mount. /// </summary> /// <param name="name">Name of the mount to delete.</param> /// <returns>True if successful. False otherwise.</returns> public async Task <bool> SysMountDelete(string name) { string path = MountPointPath + pathMounts + name; VaultDataResponseObjectB vdro = await ParentVault._httpConnector.DeleteAsync(path, "SysMountDelete"); if (vdro.Success) { return(true); } return(false); }
/// <summary> /// Creates or Updates a given policy object. /// </summary> /// <param name="policyContainerItem">The VaultPolicyContainer item that should be persisted into the Vault Instance Store.</param> /// <returns>True if successfully saved into Vault Instance. False otherwise.</returns> public async Task <bool> SysPoliciesACLCreate(VaultPolicyContainer policyContainerItem) { // Build Path string path = MountPointPath + "policies/acl/" + policyContainerItem.Name; int count = policyContainerItem.PolicyPaths.Count; // If no policy paths defined, then return - nothing to do. if (count == 0) { return(false); } // Build the JSON - Lots of string escaping, etc. fun! StringBuilder jsonBody = new StringBuilder(); // Build the body of the JSON policy out. We add the prefix part only if there is a body. foreach (VaultPolicyPathItem item in policyContainerItem.PolicyPaths.Values) { jsonBody.Append(item.ToVaultHCLPolicyFormat()); } // If the VaultPolicyPathItem is still at new initialized state then throw error as there is no permission settings to send to Vault. if (jsonBody.Length == 0) { throw new ArgumentException( "The PolicyContainer contained one or more VaultPolicyPathItem(s) at their initial state - undefined. You must supply a VaultPolicyPathItem with at least one permission set."); } jsonBody.Insert(0, "{\"policy\": \""); // Issue the policy documents closing quote and then end the JSON. jsonBody.Append("\"}"); //jsonBody.Append("}"); string json = jsonBody.ToString(); VaultDataResponseObjectB vdro = await ParentVault._httpConnector.PutAsync(path, "SysPoliciesACLCreate", null, json); if (vdro.Success) { return(true); } else { return(false); } }
/// <summary> /// Reads the configuration for the given backend mount point. /// </summary> /// <param name="mountPath">The Name(path) of the backend to read the configuration for.</param> /// <returns><see cref="VaultSysMountConfig"/>VaultSysMountConfig object containing the configuration settings.</returns> public async Task <VaultSysMountConfig> SysMountReadConfig(string mountPath) { // Build Path string path = MountPointPath + pathMounts + mountPath + "/tune"; VaultDataResponseObjectB vdro = await ParentVault._httpConnector.GetAsync_B(path, "SysMountReadConfig", null); if (vdro.Success) { return(await vdro.GetDotNetObject <VaultSysMountConfig>()); } return(null); }
/// <summary> /// Disables (deletes? Not Sure) the specified audit device /// </summary> /// <param name="auditDeviceName">Name of the Audit device to delete.</param> /// <returns>True if audit device successfully deleted. False otherwise.</returns> public async Task <bool> AuditDisable(string auditDeviceName) { string path = MountPointPath + "audit/" + auditDeviceName; VaultDataResponseObjectB vdro = await ParentVault._httpConnector.DeleteAsync(path, "SysAuditDisable"); if (vdro.Success) { return(true); } else { return(false); } }
/// <summary> /// Performs an HTTP Delete operation. /// </summary> /// <param name="APIPath">The Vault path to call to perform a deletion on.</param> /// <param name="callingRoutineName">Routine that called this function</param> /// <returns>VaultDateResponseObject of the results of the operation.</returns> public async Task <VaultDataResponseObjectB> DeleteAsync(string APIPath, string callingRoutineName) { string fullURI = APIPath; HttpResponseMessage response = await _httpClt.DeleteAsync(fullURI); if (response.IsSuccessStatusCode) { VaultDataResponseObjectB vdr = new VaultDataResponseObjectB(response); return(vdr); } await HandleVaultErrors(response, fullURI, callingRoutineName); return(null); }
/// <summary> /// Returns true if the authentication provider with the given name exists. False otherwise. /// </summary> /// <param name="authName"></param> /// <returns></returns> public async Task <bool> AuthExists(string authName) { string path = MountPointPath + "auth"; VaultDataResponseObjectB vdro = await ParentVault._httpConnector.GetAsync_B(path, "AuthExists"); if (vdro.Success) { Dictionary <string, AuthMethod> methods = await vdro.GetDotNetObject <Dictionary <string, AuthMethod> >(); // Now see if path exists - Auth names from vault have a trailing slash. if (methods.ContainsKey(authName + "/")) { return(true); } } return(false); }
/// <summary> /// Deletes a given policy. /// </summary> /// <param name="policyName">The name of the policy to delete.</param> /// <returns>True if successful in deleting.</returns> public async Task <bool> SysPoliciesACLDelete(string policyName) { // Build Path string path = MountPointPath + "policies/acl/" + policyName; try { VaultDataResponseObjectB vdro = await ParentVault._httpConnector.DeleteAsync(path, "SysPoliciesACLDelete"); if (vdro.Success) { return(true); } else { return(false); } } catch (VaultInvalidPathException) { return(false); } }
/// <summary> /// Retrieves data from the Vault. /// </summary> /// <param name="APIPath">Path to the vault method you wish to execute.</param> /// <param name="callingRoutineName">Name of routine that is calling us - used during error reporting.</param> /// <param name="sendParameters">The parameters to send to the API method.</param> /// <returns>A VaultDataResponseObject containing the return data or error codes.</returns> public async Task <VaultDataResponseObjectB> GetAsync_B(string APIPath, string callingRoutineName, Dictionary <string, string> sendParameters = null) { string fullURI; // Build the fullURI string. If it has parameters those are a part of it, otherwise it's just the APIPath if (sendParameters != null) { // Assume 30 characters per parameter item. StringBuilder sendParams = new StringBuilder("?", sendParameters.Count * 30); foreach (KeyValuePair <string, string> item in sendParameters) { sendParams.Append(item.Key + "=" + item.Value + "&"); } // Remove trailing & sendParams.Length--; fullURI = APIPath + sendParams.ToString(); } else { fullURI = APIPath; } HttpResponseMessage response = await _httpClt.GetAsync(fullURI); if (response.IsSuccessStatusCode) { VaultDataResponseObjectB vdr = new VaultDataResponseObjectB(response); return(vdr); } else { // Process errors. This method will always throw an error. await HandleVaultErrors(response, fullURI, callingRoutineName); return(null); } }
/// <summary> /// Lists all authentication methods in the current Vault System. /// <returns>Dictionary\string,AuthMethod> containing all Authentication Methods</returns> /// </summary> public async Task <Dictionary <string, AuthMethod> > AuthListAll() { string path = MountPointPath + "auth"; VaultDataResponseObjectB vdro = await ParentVault._httpConnector.GetAsync_B(path, "AuthListAll"); if (vdro.Success) { Dictionary <string, AuthMethod> methods = await vdro.GetDotNetObject <Dictionary <string, AuthMethod> >(); // We need to place the dictionary key into each objects path value. foreach (KeyValuePair <string, AuthMethod> kv in methods) { kv.Value.Path = kv.Key; } return(methods); } throw new ApplicationException("KeyValueSecretEngine:ListSecrets Arrived at unexpected code block."); }
/// <summary> /// Creates a new audit device with the specified name. /// </summary> /// <param name="auditorName">A name to be given to the audit device</param> /// <param name="filePath">A full path and filename specification of where the audit entries should be written.</param> /// <param name="description">A description of the audit device.</param> /// <returns>True if successfully created.</returns> public async Task <bool> AuditEnableFileDevice(string auditorName, string filePath, string description = "Audit to file") { string path = MountPointPath + "audit/" + auditorName; Dictionary <string, string> contentParams = new Dictionary <string, string>() { { "description", description }, { "type", "file" } }; string inputVarsJSON = VaultSerializationHelper.ToJson(contentParams); //JsonConvert.SerializeObject (contentParams, Formatting.None); Dictionary <string, string> optionsList = new Dictionary <string, string>() { //{ "path",@"c:\temp\avault.log" } { "path", filePath } }; // Build entire JSON Body: Input Params + Bulk Items List. string bulkJSON = JsonConvert.SerializeObject(new { options = optionsList }, Formatting.None); // Combine the 2 JSON's if (contentParams.Count > 0) { string newVarsJSON = inputVarsJSON.Substring(1, inputVarsJSON.Length - 2) + ","; bulkJSON = bulkJSON.Insert(1, newVarsJSON); } VaultDataResponseObjectB vdro = await ParentVault._httpConnector.PutAsync(path, "SysAuditEnableFileDevice", null, bulkJSON); return(vdro.Success); //TODO Cleanup //if ( vdro.HttpStatusCode == 204 ) { return true; } //else { return false; } }
/// <summary> /// Returns a list of all ACL Policies in the Vault Instance /// </summary> /// <returns>List[string] of all ACL policies by name.</returns> public async Task <List <string> > SysPoliciesACLList() { // Build Path string path = MountPointPath + "policies/acl"; // Setup List Parameters Dictionary <string, string> sendParams = new Dictionary <string, string>(); sendParams.Add("list", "true"); VaultDataResponseObjectB vdro = await ParentVault._httpConnector.GetAsync_B(path, "SysPoliciesACLList", sendParams); return(await vdro.GetDotNetObject <List <string> >("data.keys")); //TODO Cleanup /* * * string js = vdro.GetJSONPropertyValue (vdro.GetDataPackageAsJSON(), "keys"); * * List<string> keys = VaultUtilityFX.ConvertJSON<List<string>> (js); * return keys; */ }
/// <summary> /// Updates the configuration of a given system mount point. If description is null then it will not be updated. /// </summary> /// <param name="Name">The name of the mount to update</param> /// <param name="config"><see cref="VaultSysMountConfig"/>The backend's configuration changes</param> /// <param name="description">If set, the description will be updated. </param> /// <returns>True if successfull. False otherwise.</returns> public async Task <bool> SysMountUpdateConfig(string Name, VaultSysMountConfig config, string description = null) { string path = MountPointPath + pathMounts + Name + "/tune"; Dictionary <string, string> content = new Dictionary <string, string> { { "default_lease_ttl", config.DefaultLeaseTTL }, { "max_lease_ttl", config.MaxLeaseTTL }, { "audit_non_hmac_request_keys", config.RequestKeysToNotAuditViaHMAC }, { "audit_non_hmac_response_keys", config.ResponseKeysToNotAuditViaHMAC }, { "listing_visibility", config.VisibilitySetting }, { "passthrough_request_headers", config.PassThruRequestHeaders } }; if (description != null) { content.Add("description", description); } VaultDataResponseObjectB vdro = await ParentVault._httpConnector.PostAsync_B(path, "SysMountUpdateConfig", content, false); return(vdro.Success); }
/// <summary> /// Creates (Enables in Vault terminology) a new backend secrets engine with the given name, type and configuration settings. /// Throws: [VaultInvalidDataException] when the mount point already exists. SpecificErrorCode will be set to: [BackendMountAlreadyExists] /// <param name="mountPath">The root path to this secrets engine that it will be mounted at. Is a part of every URL to this backend.</param> /// <param name="description">Brief human friendly name for the mount.</param> /// <param name="backendType">The type of secrets backend this mount is. </param> /// <param name="config">The configuration to be applied to this mount.</param> /// <returns>Bool: True if successful in creating the backend mount point. False otherwise.</returns> /// </summary> public async Task <bool> SysMountCreate(string mountPath, string description, EnumSecretBackendTypes backendType, VaultSysMountConfig config = null) { // The keyname forms the last part of the path string path = MountPointPath + pathMounts + mountPath; // Build out the parameters dictionary. Dictionary <string, object> createParams = new Dictionary <string, object>(); // Build Options Dictionary Dictionary <string, string> options = new Dictionary <string, string>(); string typeName = ""; switch (backendType) { case EnumSecretBackendTypes.Transit: typeName = "transit"; break; case EnumSecretBackendTypes.Secret: typeName = "kv"; break; case EnumSecretBackendTypes.AWS: typeName = "aws"; throw new NotImplementedException(); case EnumSecretBackendTypes.CubbyHole: typeName = "cubbyhole"; throw new NotImplementedException(); case EnumSecretBackendTypes.Generic: typeName = "generic"; throw new NotImplementedException(); case EnumSecretBackendTypes.PKI: typeName = "pki"; throw new NotImplementedException(); case EnumSecretBackendTypes.SSH: typeName = "ssh"; throw new NotImplementedException(); case EnumSecretBackendTypes.KeyValueV2: // It is the same type as a version 1, but it has an additional config value. typeName = "kv"; options.Add("version", "2"); break; } createParams.Add("type", typeName); createParams.Add("description", description); createParams.Add("options", options); if (config != null) { createParams.Add("config", config); } try { VaultDataResponseObjectB vdro = await ParentVault._httpConnector.PostAsync_B(path, "SysMountEnable", createParams, false); if (vdro.HttpStatusCode == 204) { return(true); } else { return(false); } } catch (VaultInvalidDataException e) { if (e.Message.Contains("path is already in use")) { e.SpecificErrorCode = EnumVaultExceptionCodes.BackendMountAlreadyExists; } throw e; } }