public void Test_Decode_OrderChallengeForDns01_ForMultiDns()
        {
            var testCtx = SetTestContext();

            var oldOrder = testCtx.GroupLoadObject <OrderDetails>("order.json");
            var oldAuthz = testCtx.GroupLoadObject <Authorization[]>("order-authz.json");

            var authzIndex = 0;

            foreach (var authz in oldAuthz)
            {
                var chlngIndex = 0;
                foreach (var chlng in authz.Challenges.Where(
                             x => x.Type == Dns01ChallengeValidationDetails.Dns01ChallengeType))
                {
                    Log.LogInformation("Decoding Authorization {0} Challenge {1}",
                                       authzIndex, chlngIndex);

                    var chlngDetails = AuthorizationDecoder.ResolveChallengeForDns01(
                        authz, chlng, Clients.Acme.Signer);

                    Assert.Equal(Dns01ChallengeValidationDetails.Dns01ChallengeType,
                                 chlngDetails.ChallengeType, ignoreCase: true);
                    Assert.NotNull(chlngDetails.DnsRecordName);
                    Assert.NotNull(chlngDetails.DnsRecordValue);
                    Assert.Equal("TXT", chlngDetails.DnsRecordType, ignoreCase: true);

                    testCtx.GroupSaveObject($"order-authz_{authzIndex}-chlng_{chlngIndex}.json",
                                            chlngDetails);
                    ++chlngIndex;
                }
                ++authzIndex;
            }
        }
Ejemplo n.º 2
0
        private Task DecodeOrderAuthorizationChallenges(ACMESharp.Crypto.JOSE.IJwsTool signer)
        {
            foreach (var authz in _lastOrder.Authorizations)
            {
                var miscList = new List <Challenge>();
                foreach (var ch in authz.Details.Challenges)
                {
                    switch (ch.Type)
                    {
                    case Dns01ChallengeValidationDetails.Dns01ChallengeType:
                        authz.DnsChallenge = AuthorizationDecoder.ResolveChallengeForDns01(
                            authz.Details, ch, signer);
                        miscList.Add(ch);
                        break;

                    case Http01ChallengeValidationDetails.Http01ChallengeType:
                        authz.HttpChallenge = AuthorizationDecoder.ResolveChallengeForHttp01(
                            authz.Details, ch, signer);
                        miscList.Add(ch);
                        break;

                    default:
                        miscList.Add(ch);
                        break;
                    }
                }
                authz.MiscChallenges = miscList.ToArray();
            }

            return(Task.CompletedTask);
        }
Ejemplo n.º 3
0
        public async Task <IList <AcmeChallengeResult> > Dns01Authorization([ActivityTrigger] string[] authorizationUrls)
        {
            var acmeProtocolClient = await _acmeProtocolClientFactory.CreateClientAsync();

            var challengeResults = new List <AcmeChallengeResult>();

            foreach (var authorizationUrl in authorizationUrls)
            {
                // Authorization の詳細を取得
                var authorization = await acmeProtocolClient.GetAuthorizationDetailsAsync(authorizationUrl);

                // DNS-01 Challenge の情報を拾う
                var challenge = authorization.Challenges.First(x => x.Type == "dns-01");

                var challengeValidationDetails = AuthorizationDecoder.ResolveChallengeForDns01(authorization, challenge, acmeProtocolClient.Signer);

                // Challenge の情報を保存する
                challengeResults.Add(new AcmeChallengeResult
                {
                    Url            = challenge.Url,
                    DnsRecordName  = challengeValidationDetails.DnsRecordName,
                    DnsRecordValue = challengeValidationDetails.DnsRecordValue
                });
            }

            // Azure DNS zone の一覧を取得する
            var zones = await _dnsManagementClient.Zones.ListAllAsync();

            // DNS-01 の検証レコード名毎に Azure DNS に TXT レコードを作成
            foreach (var lookup in challengeResults.ToLookup(x => x.DnsRecordName))
            {
                var dnsRecordName = lookup.Key;

                var zone = zones.Where(x => dnsRecordName.EndsWith($".{x.Name}", StringComparison.OrdinalIgnoreCase))
                           .OrderByDescending(x => x.Name.Length)
                           .First();

                var resourceGroup = ExtractResourceGroup(zone.Id);

                // Challenge の詳細から Azure DNS 向けにレコード名を作成
                var acmeDnsRecordName = dnsRecordName.Replace($".{zone.Name}", "", StringComparison.OrdinalIgnoreCase);

                // 既存の TXT レコードがあれば取得する
                var recordSet = await _dnsManagementClient.RecordSets.GetOrDefaultAsync(resourceGroup, zone.Name, acmeDnsRecordName, RecordType.TXT) ?? new RecordSet();

                // TXT レコードに TTL と値をセットする
                recordSet.TTL        = 60;
                recordSet.TxtRecords = lookup.Select(x => new TxtRecord(new[] { x.DnsRecordValue })).ToArray();

                await _dnsManagementClient.RecordSets.CreateOrUpdateAsync(resourceGroup, zone.Name, acmeDnsRecordName, RecordType.TXT, recordSet);
            }

            return(challengeResults);
        }
Ejemplo n.º 4
0
        public async Task <(IReadOnlyList <AcmeChallengeResult>, int)> Dns01Authorization([ActivityTrigger] IReadOnlyList <string> authorizationUrls)
        {
            var acmeProtocolClient = await _acmeProtocolClientFactory.CreateClientAsync();

            var challengeResults = new List <AcmeChallengeResult>();

            foreach (var authorizationUrl in authorizationUrls)
            {
                // Authorization の詳細を取得
                var authorization = await acmeProtocolClient.GetAuthorizationDetailsAsync(authorizationUrl);

                // DNS-01 Challenge の情報を拾う
                var challenge = authorization.Challenges.First(x => x.Type == "dns-01");

                var challengeValidationDetails = AuthorizationDecoder.ResolveChallengeForDns01(authorization, challenge, acmeProtocolClient.Signer);

                // Challenge の情報を保存する
                challengeResults.Add(new AcmeChallengeResult
                {
                    Url            = challenge.Url,
                    DnsRecordName  = challengeValidationDetails.DnsRecordName,
                    DnsRecordValue = challengeValidationDetails.DnsRecordValue
                });
            }

            // DNS zone の一覧を取得する
            var zones = await _dnsProvider.ListZonesAsync();

            // DNS-01 の検証レコード名毎に DNS に TXT レコードを作成
            foreach (var lookup in challengeResults.ToLookup(x => x.DnsRecordName))
            {
                var dnsRecordName = lookup.Key;

                var zone = zones.Where(x => dnsRecordName.EndsWith($".{x.Name}", StringComparison.OrdinalIgnoreCase))
                           .OrderByDescending(x => x.Name.Length)
                           .First();

                // Challenge の詳細から DNS 向けにレコード名を作成
                var acmeDnsRecordName = dnsRecordName.Replace($".{zone.Name}", "", StringComparison.OrdinalIgnoreCase);

                await _dnsProvider.DeleteTxtRecordAsync(zone, acmeDnsRecordName);

                await _dnsProvider.CreateTxtRecordAsync(zone, acmeDnsRecordName, lookup.Select(x => x.DnsRecordValue));
            }

            return(challengeResults, _dnsProvider.PropagationSeconds);
        }
Ejemplo n.º 5
0
        public static async Task <ChallengeResult> Dns01Authorization([ActivityTrigger] DurableActivityContext context, ILogger log)
        {
            var authzUrl = context.GetInput <string>();

            var acme = await CreateAcmeClientAsync();

            var authz = await acme.GetAuthorizationDetailsAsync(authzUrl);

            // DNS-01 Challenge の情報を拾う
            var challenge = authz.Challenges.First(x => x.Type == "dns-01");

            var challengeValidationDetails = AuthorizationDecoder.ResolveChallengeForDns01(authz, challenge, acme.Signer);

            // Azure DNS の TXT レコードを書き換え
            var dnsClient = await CreateDnsManagementClientAsync();

            var zone = (await dnsClient.Zones.ListAsync()).First(x => challengeValidationDetails.DnsRecordName.EndsWith(x.Name));

            var resourceId = ParseResourceId(zone.Id);

            // Challenge の詳細から Azure DNS 向けにレコード名を作成
            var acmeDnsRecordName = challengeValidationDetails.DnsRecordName.Replace("." + zone.Name, "");

            RecordSet recordSet;

            try
            {
                recordSet = await dnsClient.RecordSets.GetAsync(resourceId["resourceGroups"], zone.Name, acmeDnsRecordName, RecordType.TXT);
            }
            catch
            {
                recordSet = null;
            }

            if (recordSet != null)
            {
                if (recordSet.Metadata == null || !recordSet.Metadata.TryGetValue(nameof(context.InstanceId), out var instanceId) || instanceId != context.InstanceId)
                {
                    recordSet.Metadata = new Dictionary <string, string>
                    {
                        { nameof(context.InstanceId), context.InstanceId }
                    };

                    recordSet.TxtRecords.Clear();
                }

                recordSet.TTL = 60;

                // 既存の TXT レコードに値を追加する
                recordSet.TxtRecords.Add(new TxtRecord(new[] { challengeValidationDetails.DnsRecordValue }));
            }
            else
            {
                // 新しく TXT レコードを作成する
                recordSet = new RecordSet
                {
                    TTL      = 60,
                    Metadata = new Dictionary <string, string>
                    {
                        { nameof(context.InstanceId), context.InstanceId }
                    },
                    TxtRecords = new[]
                    {
                        new TxtRecord(new[] { challengeValidationDetails.DnsRecordValue })
                    }
                };
            }

            await dnsClient.RecordSets.CreateOrUpdateAsync(resourceId["resourceGroups"], zone.Name, acmeDnsRecordName, RecordType.TXT, recordSet);

            return(new ChallengeResult
            {
                Url = challenge.Url,
                DnsRecordName = challengeValidationDetails.DnsRecordName,
                DnsRecordValue = challengeValidationDetails.DnsRecordValue
            });
        }
Ejemplo n.º 6
0
        private async Task <ChallengeResult> DnsAuthorizationAsync(string authorizationUrl, string instanceId)
        {
            var acmeProtocolClient = await CreateAcmeClientAsync();

            var authorizationDetails = await acmeProtocolClient.GetAuthorizationDetailsAsync(authorizationUrl);

            var challenge = authorizationDetails.Challenges.First(x => x.Type == "dns-01");
            var challengeValidationDetails = AuthorizationDecoder.ResolveChallengeForDns01(authorizationDetails, challenge, acmeProtocolClient.Signer);

            var dnsManagementClient = await CreateDnsManagementClientAsync();

            var zone              = (await dnsManagementClient.Zones.ListAsync()).First(x => challengeValidationDetails.DnsRecordName.EndsWith(x.Name));
            var resourceId        = ParseResourceId(zone.Id);
            var acmeDnsRecordName = challengeValidationDetails.DnsRecordName.Replace("." + zone.Name, "");

            RecordSetInner recordSet;

            try
            {
                recordSet = await dnsManagementClient.RecordSets.GetAsync(resourceId["resourceGroups"], zone.Name, acmeDnsRecordName, RecordType.TXT);
            }
            catch
            {
                recordSet = null;
            }

            if (recordSet != null)
            {
                if (recordSet.Metadata == null || !recordSet.Metadata.TryGetValue("InstanceId", out var dnsInstanceId) || dnsInstanceId != instanceId)
                {
                    recordSet.Metadata = new Dictionary <string, string>
                    {
                        { "InstanceId", instanceId }
                    };

                    recordSet.TxtRecords.Clear();
                }

                recordSet.TTL = 60;
                recordSet.TxtRecords.Add(new TxtRecord(new[] { challengeValidationDetails.DnsRecordValue }));
            }
            else
            {
                recordSet = new RecordSetInner()
                {
                    TTL      = 60,
                    Metadata = new Dictionary <string, string>
                    {
                        { "InstanceId", instanceId }
                    },
                    TxtRecords = new[]
                    {
                        new TxtRecord(new[] { challengeValidationDetails.DnsRecordValue })
                    }
                };
            }

            await dnsManagementClient.RecordSets.CreateOrUpdateAsync(resourceId["resourceGroups"], zone.Name, acmeDnsRecordName, RecordType.TXT, recordSet);

            return(new ChallengeResult()
            {
                Url = challenge.Url,
                DnsRecordName = challengeValidationDetails.DnsRecordName,
                DnsRecordValue = challengeValidationDetails.DnsRecordValue
            });
        }