c# - 获取 Azure 通知中心的 APNS 证书
问题描述
我想创建一个应用程序,以便我可以审核我们所有的 200 多个通知中心。这主要是为即将到期的 APNS 查找证书。
我可以在 PowerShell 中很好地做到这一点,但我无法在 C# 中做到这一点,因为 Fluent SDK 没有像 PowerShell 这样的凭据方法。
var credentials = SdkContext.AzureCredentialsFactory
.FromServicePrincipal(clientId,
clientSecret,
tenantId,
AzureEnvironment.AzureGlobalCloud);
var azure = Azure
.Configure()
.Authenticate(credentials)
.WithDefaultSubscription();
NotificationHubsManagementClient nhClient = new NotificationHubsManagementClient(credentials);
nhClient.SubscriptionId = subscriptionId;
var nhNamespaces = nhClient.Namespaces.ListAllAsync().Result;
foreach (var nhNamespace in nhNamespaces)
{
var nhHubs = nhClient.NotificationHubs.ListAsync(resourceGroupName, nhNamespace.Name).Result;
foreach (var nhHub in nhHubs)
{
var hub = nhClient.NotificationHubs.GetAsync(resourceGroupName, nhNamespace.Name, nhHub.Name).Result;
//THEY ARE ALWAYS NULL AND THERE IS NO METHOD TO GET THE APNS CREDENTIALS
if (hub.ApnsCredential != null)
{
var apnsCred = hub.ApnsCredential;
Console.WriteLine(apnsCred.ApnsCertificate);
}
}
}
在 PowerShell 中,我可以调用:
$pnsCred = Get-AzureRmNotificationHubPNSCredentials -ResourceGroup $resourceGroup -Namespace $hubNamespaceName -NotificationHub $hub.Name
我需要一种在 C# 中获取集线器凭据的方法。
我几乎最终的解决方案(需要更多的重构和错误处理):
using Microsoft.Azure.Management.NotificationHubs.Fluent;
using Microsoft.Azure.Management.NotificationHubs.Fluent.Models;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Linq;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using mpu.sql;
using mpu.snow;
using mpu.helpers;
namespace mpu.azure
{
public static class NotificationHubHelper
{
private static string tenantId = ConfigurationManager.AppSettings["nhIda:tenantId"];
private static string clientId = ConfigurationManager.AppSettings["nhIda:clientId"];
private static string clientSecret = ConfigurationManager.AppSettings["nhIda:clientSecret"];
private static string resourceGroupName = ConfigurationManager.AppSettings["nhIda:resourceGroupName"];
private static string subscriptionId = ConfigurationManager.AppSettings["nhIda:subscriptionId"];
private static DateTime expiryCheck = DateTime.Now.AddDays(-30);
public static void CheckHubApnsCerts()
{
var credentials = SdkContext.AzureCredentialsFactory
.FromServicePrincipal(clientId,
clientSecret,
tenantId,
AzureEnvironment.AzureGlobalCloud);
NotificationHubsManagementClient nhClient = new NotificationHubsManagementClient(credentials);
nhClient.SubscriptionId = subscriptionId;
var nhNamespaces = nhClient.Namespaces.ListAllAsync().Result;
nhNamespaces.AsParallel().ForAll(nhNamespace =>
{
var nhHubs = nhClient.NotificationHubs.ListAsync(resourceGroupName, nhNamespace.Name).Result;
nhHubs.AsParallel().ForAll(async (nhHub) =>
{
PnsCredentialResponse pnsCredential = await GetPnsCredential(nhNamespace, nhHub, nhClient.ApiVersion);
if (!string.IsNullOrEmpty(pnsCredential?.properties?.apnsCredential?.properties?.apnsCertificate))
{
var certRawValue = pnsCredential.properties.apnsCredential.properties.apnsCertificate;
var certKey = pnsCredential.properties.apnsCredential.properties.certificateKey;
var cert = new X509Certificate2(Convert.FromBase64String(certRawValue), certKey, X509KeyStorageFlags.MachineKeySet
| X509KeyStorageFlags.PersistKeySet
| X509KeyStorageFlags.Exportable);
Console.ForegroundColor = ConsoleColor.Green;
if (cert.NotAfter <= expiryCheck)
{
Console.ForegroundColor = ConsoleColor.Red;
try
{
var certIncident = SqlHelper.GetRecordByCertThumb(cert.Thumbprint);
if (certIncident == null)
{
var incidentNumber = SnowIncidents.CreateP2Incident($"Notification Hub APNS Certificate Expiring {nhHub.Name}", $"The notification hub APNS certificate for hub {nhHub.Name} is due to expire on {cert.NotAfter}. Please verify in Azure and request a new certificate from the client ASAP.");
if (!string.IsNullOrEmpty(incidentNumber))
SqlHelper.CreateIncidentRecord(cert.Thumbprint, incidentNumber);
}
}
catch
{
EmailHelper.SendCertExpiryEmailForNotificationHub(nhHub.Name, cert.NotAfter);
}
}
Console.WriteLine($"{nhHub.Name} - {cert.NotAfter} - {cert.Thumbprint}");
}
});
});
}
private static async Task<PnsCredentialResponse> GetPnsCredential(NamespaceResourceInner nhNamespace, NotificationHubResourceInner nhHub, string apiVerion)
{
var requestString = $"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.NotificationHubs/namespaces/{nhNamespace.Name}/notificationHubs/{nhHub.Name}/pnsCredentials?api-version={apiVerion}";
var client = new RestClient(requestString);
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", $"Bearer {await GetAccessToken(tenantId, clientId, clientSecret)}");
IRestResponse response = client.Execute(request);
var pnsCredential = JsonConvert.DeserializeObject<PnsCredentialResponse>(response.Content);
return pnsCredential;
}
private static async Task<string> GetAccessToken(string tenantId, string clientId, string clientKey)
{
string authContextURL = "https://login.windows.net/" + tenantId;
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential(clientId, clientKey);
var result = await authenticationContext
.AcquireTokenAsync("https://management.azure.com/", credential);
if (result == null)
throw new InvalidOperationException("Failed to obtain the JWT token for management.azure.com");
return result.AccessToken;
}
}
public class PnsCredentialResponse
{
public string id { get; set; }
public string name { get; set; }
public string type { get; set; }
public object location { get; set; }
public object tags { get; set; }
public Properties properties { get; set; }
}
public class Properties
{
public Apnscredential apnsCredential { get; set; }
}
public class Apnscredential
{
[JsonProperty("properties")]
public ApnsProperties properties { get; set; }
}
public class ApnsProperties
{
public string endpoint { get; set; }
public string apnsCertificate { get; set; }
public string certificateKey { get; set; }
public string thumbprint { get; set; }
}
}
解决方案
Azure PowerShell 模块将构建在管理 SDK 之上。最新版本可以在 NuGet上找到。这些 SDK 的源代码可以在 GitHub 上找到。如果没记错的话,我相信该NamespaceOperations.GetWithHttpMessagesAsync
方法就是您正在寻找的方法。
值得注意的是,管理功能以前在 NotificationHubs SDK 本身的 v1 中。它在 v2 中被删除,以防止混淆有多种方法来做同样的事情。然而,普遍的需求是恢复管理功能,以便有一个包可以与通知中心的所有东西一起使用。在创作时,这些更改正在审核中。
推荐阅读
- python - 找不到文件错误 Ray 安装 Windows
- visual-studio - 无法从另一类业务逻辑层访问公共类的 DataAccess 层
- java - 找到 sum = K 的子数组(连续)的数量(考虑时间复杂度)
- javascript - JavaScript 在单击时更改网格单元格的背景颜色
- kubernetes - 将子路径作为我在 k3s 上的后端服务的“根”路径?
- python - googletrans JSON解码错误
- bpmn - Camunda 使用任务变量返回不正确的任务列表
- javascript - 无法使用 XMLHttpRequest 将参数传递给 $_POST
- i18next - 如何使用 react-i18next
命名标签? - php - 更新到 WSL2 后无法从 PhpStorm 连接到 Xdebug