in src/governance/client/Controllers/WorkspacesController.cs [34:140]
public async Task<IActionResult> SetWorkspaceConfig(
[FromForm] WorkspaceConfigurationModel model)
{
if (model.SigningCertPemFile == null && string.IsNullOrEmpty(model.SigningCertId))
{
return this.BadRequest("Either SigningCertPemFile or SigningCertId must be specified");
}
if (model.SigningCertPemFile != null && !string.IsNullOrEmpty(model.SigningCertId))
{
return this.BadRequest(
"Only one of SigningCertPemFile or SigningCertId must be specified");
}
CoseSignKey coseSignKey;
X509Certificate2 httpsClientCert;
if (model.SigningCertPemFile != null)
{
if (model.SigningCertPemFile.Length <= 0)
{
return this.BadRequest("No signing cert file was uploaded.");
}
if (model.SigningKeyPemFile == null || model.SigningKeyPemFile.Length <= 0)
{
return this.BadRequest("No signing key file was uploaded.");
}
string signingCert;
using var reader = new StreamReader(model.SigningCertPemFile.OpenReadStream());
signingCert = await reader.ReadToEndAsync();
string signingKey;
using var reader2 = new StreamReader(model.SigningKeyPemFile.OpenReadStream());
signingKey = await reader2.ReadToEndAsync();
coseSignKey = new CoseSignKey(signingCert, signingKey);
httpsClientCert = X509Certificate2.CreateFromPem(signingCert, signingKey);
}
else
{
Uri signingCertId;
try
{
signingCertId = new Uri(model.SigningCertId!);
}
catch (Exception e)
{
return this.BadRequest($"Invalid signingKid value: {e.Message}.");
}
var creds = new DefaultAzureCredential();
coseSignKey = await CoseSignKey.FromKeyVault(signingCertId, creds);
// Download the full cert along with private key for HTTPS client auth.
var akvEndpoint = "https://" + signingCertId.Host;
var certClient = new CertificateClient(new Uri(akvEndpoint), creds);
// certificates/{name} or certificates/{name}/{version}
var parts = signingCertId.AbsolutePath.Split(
"/",
StringSplitOptions.RemoveEmptyEntries);
string certName = parts[1];
string? version = parts.Length == 3 ? parts[2] : null;
httpsClientCert = await certClient.DownloadCertificateAsync(certName, version);
}
string ccfEndpoint = string.Empty;
if (!string.IsNullOrEmpty(model.CcfEndpoint))
{
ccfEndpoint = model.CcfEndpoint.Trim();
try
{
_ = new Uri(ccfEndpoint);
}
catch (Exception e)
{
return this.BadRequest($"Invalid ccfEndpoint value '{ccfEndpoint}': {e.Message}.");
}
}
string serviceCertPem = string.Empty;
if (model.ServiceCertPemFile != null)
{
using (var reader3 = new StreamReader(model.ServiceCertPemFile.OpenReadStream()))
{
serviceCertPem = await reader3.ReadToEndAsync();
}
}
// Governance endpoint uses Cose signed messages for member auth.
CcfClientManager.SetGovAuthDefaults(coseSignKey);
// App authentication uses member_cert authentication policy which uses HTTPS client cert
// based authentication. So we need access to the member cert and private key for setting
// up HTTPS client cert auth.
CcfClientManager.SetAppAuthDefaults(httpsClientCert);
// Set workspace configuration values only if the CCF endpoint is specified as part of the
// configure call. This serves as a default value when running in single CCF client mode.
if (!string.IsNullOrEmpty(ccfEndpoint))
{
CcfClientManager.SetCcfDefaults(ccfEndpoint, serviceCertPem);
}
return this.Ok("Workspace details configured successfully.");
}