public async Task <JObject> GetReadableAccessorAsync(OutputObjectAccessorRequest accessorRequest) { var urlRequest = CreateUrlRequest(accessorRequest); var url = await urlProvider.GetReadableUrlAsync(urlRequest); if (!string.IsNullOrEmpty(accessorRequest.SignatureRsaKeyXml)) { url.Signature = await urlSigner.GenerateSignatureAsync(accessorRequest.SignatureRsaKeyXml, url); } return(JObject.FromObject(url)); }
public Task <string> GenerateSignatureAsync(string rsaKeyXml, HttpExecutionRequest toSign) { if (string.IsNullOrEmpty(rsaKeyXml)) { throw new ArgumentNullException(nameof(rsaKeyXml)); } if (toSign == null) { throw new ArgumentNullException(nameof(toSign)); } // Convert the execution request to a canonical string. // TODO: Document this string format so that target extensions can verify execution request signatures. var toSignAsString = $"{toSign.ExecutionId}|" + $"{toSign.ExecutionProfileName}|" + $"{toSign.ExtensionId}|" + $"{toSign.ExtensionVersionId}|" + $"{toSign.StatusUpdateKey}|" + $"{toSign.GetExecutionStatusUrl}|" + $"{toSign.UpdateExecutionStatusUrl}"; // Use the generic string signer to sign the canonical execution request string. return(stringSigner.GenerateSignatureAsync(rsaKeyXml, toSignAsString)); }
public Task <string> GenerateSignatureAsync(string rsaKeyXml, ObjectUrl toSign) { if (string.IsNullOrEmpty(rsaKeyXml)) { throw new ArgumentNullException(nameof(rsaKeyXml)); } if (toSign == null) { throw new ArgumentNullException(nameof(toSign)); } return(stringSigner.GenerateSignatureAsync(rsaKeyXml, toSign.Url)); }
private async Task <DirectExecutionRequestApiModel> CreateDirectExecutionRequestAsync(IExecutionRequestContext erContext) { // Convert the API request context to a core execution request... var execRequest = ToExecutionRequestAsync(erContext); // Then, convert the core execution request into a direct execution token... var directExecRequest = new DirectExecutionRequestApiModel { ExecutionId = execRequest.ExecutionId, ExecutionModelName = execRequest.ExecutionModelName, ExecutionProfileName = execRequest.ExecutionProfileName, ExecutionSettings = execRequest.ExtensionSettings, ExtensionId = execRequest.ExtensionId, ExtensionVersionId = execRequest.ExtensionVersionId, GetExecutionStatusUrl = execRequest.GetExecutionStatusUrl, ObjectProviderName = execRequest.ObjectProviderName, ExecutorProperties = execRequest.ExecutorProperties, Services = await execServiceProvider.GetServiceConfigurationAsync(execRequest) }; // Based on the selected execution profile, set the expiration date/time (how long the client can use the extension directly for) // and digitally sign the execution request using the hub's private key. In this model, we assume that the target execution has the hub's // public key and can us it to verify the authenticity of the token and all the information contained therein. // For more information, see /doc/architecture/direct-execution.md. directExecRequest.ExpirationDateTimeUtc = DateTime.UtcNow.Add(erContext.ExecutionProfile.DirectExecutionTokenDuration.Value); directExecRequest.Signature = await directExecRequestSigner.GenerateSignatureAsync(execRequest.SignatureRsaKeyXml, directExecRequest); // Update the execution to indicate that a direct access token is being provided... erContext.Execution.ExecutionTimeoutDateTimeUtc = directExecRequest.ExpirationDateTimeUtc; erContext.Execution.Status = ExecutionStatus.DirectExecutionTokenProvided; erContext.Execution.LastUpdatedDateTimeUtc = DateTime.UtcNow; // Persist the execution and return the direct execution token... await UpdateExecutionAsync(erContext.Execution); return(directExecRequest); }
public Task <string> GenerateSignatureAsync(string rsaKeyXml, DirectExecutionRequestApiModel toSign) { if (string.IsNullOrEmpty(rsaKeyXml)) { throw new ArgumentNullException(nameof(rsaKeyXml)); } if (toSign == null) { throw new ArgumentNullException(nameof(toSign)); } var apiModelString = $"{toSign.ExecutionId}|" + $"{toSign.ExtensionId}|" + $"{toSign.ExtensionVersionId}|" + $"{toSign.ExecutionModelName}|" + $"{toSign.ExecutionProfileName}|" + $"{toSign.ObjectProviderName}|" + $"{toSign.GetExecutionStatusUrl}|" + $"{toSign.ExpirationDateTimeUtc.ToString("s")}"; return(stringSigner.GenerateSignatureAsync(rsaKeyXml, apiModelString)); }
public async Task <Core.Models.ExecutionContext> ExecuteAsync(ExecutionRequest execRequest, CancellationToken cancelToken) { if (execRequest == null) { throw new ArgumentNullException(nameof(execRequest)); } logger.LogInformation($"Processing execution request [{execRequest.ExecutionId}]..."); // Give all the applicable extension services a chance to do any synchronous pre-work ahead of the actual execution... // For more information on extension services, see /doc/architecture/extension-services.md. await(execRequest.ValidateOnly ? this.execServiceProvider.OnValidatingAsync(execRequest) : this.execServiceProvider.OnExecutingAsync(execRequest)); // UTC now + the execution timeout on the execution request if it was provided. // If no execution timeout was defined, default to an hour [defaultTimeoutPeriod]. execRequest.CalculateExecutionTimeoutDateTimeUtc(defaultTimeoutPeriod); logger.LogDebug($"Execution [{execRequest.ExecutionId}] timeout set to [{execRequest.ExecutionTimeoutDateTimeUtc}] UTC."); // We're about to execution the extension. Create an execution context to capture the results... var execContext = execRequest.ToExecutionContext(); try { // Deserialize the execution model-specific settings, provided in the [execRequest.extensionSettings] JSON object property, // to get the execution and/or validation URLs that we need to handle the request. var httpSettings = GetHttpExtensionSettings(execRequest); // Create the execution request that we'll POST to the extension... var httpExecRequest = await ToHttpExecutionRequestAsync(execRequest); logger.LogDebug($"Execution [{execRequest.ExecutionId}] URL is [{httpSettings.ExecutionUrl}]."); logger.LogDebug(string.IsNullOrEmpty(httpSettings.ValidationUrl) ? $"Execution [{execRequest.ExecutionId}] validation URL is [{httpSettings.ValidationUrl}]." : $"Execution [{execRequest.ExecutionId}] validation URL not provided."); // If there was a valid RSA public/private key pair provided along with the request, // sign the request before we send it along to the extension... if (!string.IsNullOrEmpty(execRequest.SignatureRsaKeyXml)) { logger.LogDebug($"Signing execution request [{execRequest.ExecutionId}]..."); httpExecRequest.Signature = await httpExecRequestSigner.GenerateSignatureAsync(execRequest.SignatureRsaKeyXml, httpExecRequest); } if (execRequest.ValidateOnly) { // If it's a validation only request, make sure that the extension actually supports validation. // Under normal circumstances, this should have been caught way further upstream at the execution API. if (execRequest.IsValidationSupported == false) { throw new NotSupportedException($"Extension [{execRequest.ExtensionId}:{execRequest.ExtensionVersionId}] " + "does not support validation."); } // Validate the request... execContext = await ValidateAsync(execContext, httpExecRequest, httpSettings); } else { // Execute the request... execContext = await ExecuteAsync(execContext, httpExecRequest, httpSettings); } } catch (Exception ex) { logger.LogError($"An error occurred while processing execution request [{execRequest.ExecutionId}]: [{ex.Message}]."); execContext.UpdateStatus(ExecutionStatus.Failed); } finally { // Give all the applicable extension services a chance to do any synchronous post-work after the execution // regardless of whether or not it succeeded. For more information on extension services, see /doc/architecture/extension-services.md. await(execRequest.ValidateOnly ? this.execServiceProvider.OnValidatedAsync(execContext) : this.execServiceProvider.OnExecutedAsync(execContext)); logger.LogInformation($"Execution request [{execRequest.ExecutionId}] processing complete."); } return(execContext); }