获取Azure通知中心的APNS证书

时间:2019-09-20 12:23:21

标签: c# certificate azure-notificationhub

我想创建一个应用程序,以便我可以审核我们所有的200多个通知中心。它主要用于查找即将过期的APNS的证书。

我可以在PowerShell中很好地完成此操作,但由于Fluent SDK没有像PowerShell这样的凭据凭证方法,因此我无法在C#中做到这一点。

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; }
    }
}

1 个答案:

答案 0 :(得分:0)

Azure PowerShell模块将建立在Management SDK之上。最新版本可以是found on NuGet。这些SDK的源代码可以为found on GitHub。如果有记忆,我相信您正在寻找NamespaceOperations.GetWithHttpMessagesAsync方法。

值得注意的是,NotificationHubs SDK本身的v1以前具有管理功能。在v2中将其删除是为了避免因采用多种方法来做同一件事而造成混淆。但是,很普遍的需求是断言管理功能已恢复,因此只有一个包可以与所有通知中心配合使用。在创作时,those changes are in review