创建生产设备提交

重要

仪表板提交 REST API 已被弃用,并且不再可用。 正在考虑为将来版本提供适用于驱动程序提交的 API。

你可以使用组织的服务帐户和文件签名服务,将认证和文件签名提交构建到现有开发和部署框架中。

创建生产设备提交请求

  1. 通过遵循管理你的服务帐户凭据中的步骤,获取组织的服务帐户凭据。 如果没有服务帐户,请按照管理你的服务帐户凭据 中的步骤操作。 你将在下一步的 client_secret 值中需要使用服务帐户凭据。

  2. 从 Azure 访问控制服务 (ACS) 获取身份验证令牌。 有关详细信息,请参阅如何从 ACS 请求 SWT 令牌。 在客户端请求该令牌时,使用以下代码。

    string realm = "https://devicesigningservice.cloudapp.net";
    string acsNameSpace = "https://sysdevacs.accesscontrol.windows.net";
    var client = new HttpClient();
    client.BaseAddress = new Uri(acsNameSpace);
    List<KeyValuePair<string, string>> values = new List<KeyValuePair<string, string>>();
    values.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
    values.Add(new KeyValuePair<string, string>("client_id", "Fabrikam"));
    values.Add(new KeyValuePair<string, string>("client_secret", "Contoso"));
    values.Add(new KeyValuePair<string, string>("scope", realm));
    var content = new FormUrlEncodedContent(values);
    var responseMessage = client.PostAsync("v2/OAuth2-13", content).Result;
    var jss = new JavaScriptSerializer();
    dynamic responseString = jss.Deserialize<dynamic>(responseMessage.Content.ReadAsStringAsync().Result);
    string token = responseString["access_token"] as string;
    
  3. 使用创建请求操作和步骤 2 中的身份验证令牌,创建仪表板提交对象对象。 身份验证令牌必须在标头中。 这将发出请求并返回一个共享访问签名 (SAS) URI。

    var json = CreateSubmissionMetadata(new {
    ProductName = "Test",
    MarketingNames = new object[]{
    new {
    Name = "Testing Name",
    Locale = new object[]{
    "English"
    }
    }
    },
    AnnouncementDate = DateTime.Now.AddDays(4).ToString("s"),
    PublishingDate = DateTime.Now.AddDays(6).ToString("s"),
    OSSelections = new object[]{
    new {
    OS = "Windows 8",
    ProductType = "Printer",
    QualificationLevel = "Signature Only"
    }
    },
    InitialUploadFileSize = 1,
    TestHarnessType = "HLK"
    });
    
            static dynamic CreateSubmissionMetadata(dynamic json)
            {
                var SysdevEndpoint = "https://devicesigningservice.cloudapp.net/api/signing/devices";
                HttpRequestMessage createRequest = new HttpRequestMessage()
                {
                    Method = HttpMethod.Post,
                    RequestUri = new Uri(SysdevEndpoint),
                    Content = new StringContent(new JavaScriptSerializer().Serialize(json).ToString())
                };
                createRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                HttpResponseMessage response = null;
                TimeAction("Creating an azure submission took {0} ms", () => { response = SendRequest(createRequest); });
    
                var submissionUrl = response.Headers.Location.ToString();
                var sasUrl = response.Content.ReadAsStringAsync().Result;
    
                return new
                {
                    SasUrl = sasUrl.Substring(1, sasUrl.Length - 2),
                    SubmissionGuid = GetFirstGuidFromUrl(submissionUrl)
                };
            }
            static HttpResponseMessage SendRequest(HttpRequestMessage message)
            {
                Trace.WriteLine("Sending request to " + message.RequestUri);
                using (HttpClient client = new HttpClient())
                {
                    //Trace.WriteLine("Set Bearer header to " + AuthToken);
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
    
                    var resp = client.SendAsync(message).Result;
                    if(resp.IsSuccessStatusCode)
                    {
                        return resp;
                    }
                    else
                    {
                        throw new HttpRequestException("The request failed with status code response: " + resp.StatusCode.ToString());
                    }
                }
            }
    
  4. 通过步骤 3 中的 SAS URI,使用 Azure 存储 API 上载你的硬件认证工具包 (HCK)。

    /// <summary>
            /// Uploads the given file using the SAS Url provided. This method can be replaced with a call to the Azure Storage Client API
            /// </summary>
            /// <param name="sasUrl">Sas Url returned from the Sysdev API</param>
            /// <param name="filepath">Path to the file that will be uploaded</param>
            static void UploadFile(string sasUrl, string filepath)
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Add("x-ms-version", Version);
                    client.DefaultRequestHeaders.Add("x-ms-client-request-id", SessionGuid);
    
                    StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?><BlockList>");
    
                    foreach (byte[] chunk in GetFileChunks(filepath))
                    {
                        var blockid = GetHash(chunk);
                        HttpRequestMessage chunkMessage = new HttpRequestMessage()
                        {
                            Method = HttpMethod.Put,
                            RequestUri = new Uri(sasUrl + "&timeout=90&comp=block&blockid=" + WebUtility.UrlEncode(blockid)),
                            Content = new ByteArrayContent(chunk)
                        };
                        chunkMessage.Headers.Add("x-ms-blob-type", "BlockBlob");
                        chunkMessage.Content.Headers.Add("MD5-Content", blockid);
    
                        TimeAction("Uploading chunk " + blockid + " took {0} ms", () =>
                        {
                            var response = client.SendAsync(chunkMessage).Result;
                        });
                        sb.Append("<Latest>");
                        sb.Append(blockid);
                        sb.Append("</Latest>");
                    }
                    sb.Append("</BlockList>");
    
                    Trace.WriteLine(sb.ToString());
    
                    HttpRequestMessage commitMessage = new HttpRequestMessage()
                    {
                        Method = HttpMethod.Put,
                        RequestUri = new Uri(sasUrl + "&timeout=90&comp=blocklist"),
                        Content = new StringContent(sb.ToString())
                    };
                    TimeAction("Commiting the blocks took {0} ms", () =>
                    {
                        var commit = client.SendAsync(commitMessage).Result;
                    });
                }
            }
    
  5. 上载完成后,通过在更新现有提交 操作中将 UpdateComplete 标志设置为 true,开始提交过程。 这将通知 Microsoft 启动后端处理。

    static void UpdateSubmission(string guid, dynamic json)
            {
                HttpRequestMessage update = new HttpRequestMessage()
                {
                    Method = new HttpMethod("PATCH"),
                    RequestUri = new Uri(SysdevEndpoint + "/" + guid),
                    Content = new StringContent(new JavaScriptSerializer().Serialize(json))
                };
                update.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    
                TimeAction("Updating the information for submission " + guid, () => { var response = SendRequest(update); });
            }
    
  6. 若要轮询状态,请使用获取现有提交的元数据 操作并评估 Status 值以响应 ApprovedManual ReviewRejected。 处理可能需要 10 分钟到 24 小时的时间。

    Trace.WriteLine("Begin waiting for the submission to finish");
                    //Poll for the status of the submission in our system
                    //Give up checking after an hour
                    for (int retryCount = 0; ; retryCount++)
                    {
                        Thread.Sleep(60 * 1000);
                        var submission = GetSubmission(resp.SubmissionGuid);
                        if (String.Compare(submission["Status"], "Completed") == 0)
                        {
                            //Once the submission is finished processing, loop through the signed files and download them
                            foreach (var asset in submission["Assets"])
                            {
                                if (String.Compare(asset["AssetType"], "SignedFile") == 0)
                                {
                                    //Download the signed files from the azure storage blob
                                    DownloadFile(resp.SubmissionGuid, asset["DeviceSigningAssetID"], Path.Combine(outputDirectory, asset["Name"]));
                                }
                            }
                            break;
                        }
                        if (retryCount == 60)
                        {
                            throw new ApplicationException("Submission is taking a long time to process, last status: " + submission["Status"]);
                        }
    

下载资源

处理完成后,执行以下操作来下载已签名文件、认证验证报告的 URL 或驱动程序更新可接受 (DUA) shell 包:

  1. 如果你的令牌已过期,请从 ACS 获取新的身份验证令牌。

  2. 使用获取现有提交的元数据操作检索仪表板提交对象

    static dynamic GetSubmission(string guid)
            {
                HttpRequestMessage update = new HttpRequestMessage()
                {
                    Method = HttpMethod.Get,
                    RequestUri = new Uri(SysdevEndpoint + "/" + guid)
                };
    
                HttpResponseMessage response = null;
               TimeAction("Getting information for submission "+guid, () => { response = SendRequest(update); });
    
                JavaScriptSerializer jss = new JavaScriptSerializer();
    
                return jss.Deserialize<dynamic>(response.Content.ReadAsStringAsync().Result);
            }
    
  3. 仪表板提交对象使用仪表板提交对象,并使用获取提交内特定资源操作检索 SAS URI。

    static Uri GetSasUrlForAsset(string submissionGuid, string assetGuid)
            {
                HttpRequestMessage asset = new HttpRequestMessage()
                {
                    Method = HttpMethod.Get,
                    RequestUri = new Uri(SysdevEndpoint + "/" + submissionGuid + "/assets/" + assetGuid)
                };
    
                HttpResponseMessage get = null;
                TimeAction("Getting the sas url for "+submissionGuid +"/"+assetGuid + "took {0} ms", ()=>{SendRequest(asset);});
    
                return get.Headers.Location;
            }
    
  4. 使用 Azure 存储 API 下载你请求的资源。

    static void DownloadFile(string submissionGuid, string assetGuid, string filepath, Uri sasUrl)
            {
              using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Add("x-ms-version", Version);
                    client.DefaultRequestHeaders.Add("x-ms-client-request-id", SessionGuid);
    
                    HttpRequestMessage download = new HttpRequestMessage()
                    {
                        Method = HttpMethod.Get,
                        RequestUri = sasUrl
                    };
    
                    using (FileStream fs = new FileStream(filepath, FileMode.CreateNew))
                    {
                        using (var stream = client.SendAsync(download).Result.Content.ReadAsStreamAsync().Result)
                        {
                            byte[] buffer = new byte[ChunkSize];
                            int size = 0;
                            while ((size = stream.Read(buffer, 0, ChunkSize)) > 0)
                            {
                                fs.Write(buffer, 0, size);
                            }
                        }
                    }
                }
            }
    

相关主题

仪表板提交 REST API 参考

仪表板提交对象

管理你的服务帐户凭据