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