public HttpChallenge DecodeChallenge()
        {
            AuthorizeChallenge challenge = _client.DecodeChallenge(_authorizationState, AcmeProtocol.CHALLENGE_TYPE_HTTP);

            _authorizationState.Challenges = new[] { challenge };
            return((HttpChallenge)challenge.Challenge);
        }
示例#2
0
        public static AuthorizationState Authorize(Target target)
        {
            List <string>             identifiers = target.GetHosts(false);
            List <AuthorizationState> authStatus  = new List <AuthorizationState>();

            foreach (var dnsIdentifier in identifiers)
            {
                string answerUri;
                var    challengeType = target.Plugin.ChallengeType;

                Log.Information("Authorizing identifier {dnsIdentifier} using {challengeType} challenge", dnsIdentifier, challengeType);
                var authzState = _client.AuthorizeIdentifier(dnsIdentifier);
                var challenge  = _client.DecodeChallenge(authzState, challengeType);
                var cleanUp    = challengeType == AcmeProtocol.CHALLENGE_TYPE_HTTP
                              ? PrepareHttpChallenge(target, challenge, out answerUri)
                              : PrepareDnsChallenge(target, challenge, out answerUri);

                try
                {
                    Log.Debug("Submitting answer");
                    authzState.Challenges = new AuthorizeChallenge[] { challenge };
                    _client.SubmitChallengeAnswer(authzState, challengeType, true);

                    // have to loop to wait for server to stop being pending.
                    // TODO: put timeout/retry limit in this loop
                    while (authzState.Status == "pending")
                    {
                        Log.Debug("Refreshing authorization");
                        Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                        var newAuthzState = _client.RefreshIdentifierAuthorization(authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            authzState = newAuthzState;
                        }
                    }

                    Log.Information("Authorization result: {Status}", authzState.Status);
                    if (authzState.Status == "invalid")
                    {
                        target.Plugin.OnAuthorizeFail(target);
                    }
                    authStatus.Add(authzState);
                }
                finally
                {
                    cleanUp(authzState);
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != "valid")
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = "valid"
            });
        }
示例#3
0
        static Tuple <AuthorizeChallenge, AuthorizationState> RequestChallengeFile(
            AcmeClient client, string domain)
        {
            var state         = client.AuthorizeIdentifier(domain);
            var challenge     = client.DecodeChallenge(state, AcmeProtocol.CHALLENGE_TYPE_HTTP);
            var httpChallenge = challenge.Challenge as HttpChallenge;

            return(new Tuple <AuthorizeChallenge, AuthorizationState>(challenge, state));
        }
        public static void Authorize(AcmeClient client, IDnsProvider dnsProvider, string hostName, List <string> alternativeNames = null)
        {
            var dnsIdentifiers = new List <string>()
            {
                hostName
            };

            if (alternativeNames != null)
            {
                dnsIdentifiers.AddRange(alternativeNames);
            }

            var authResults = new List <AuthorizationState>();

            foreach (var dnsIdentifier in dnsIdentifiers)
            {
                var authzState = client.AuthorizeIdentifier(dnsIdentifier);
                var challenge  = client.DecodeChallenge(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS);

                var dnsChallenge = challenge.Challenge as DnsChallenge;
                var dnsRecordRef = AddRecordToDNS(dnsProvider, dnsChallenge);
                Thread.Sleep(3 * 1000); //  wait for the newly created TXT record to take effect

                try
                {
                    authzState.Challenges = new AuthorizeChallenge[] { challenge };
                    client.SubmitChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS, true);

                    // have to loop to wait for server to stop being pending.
                    // todo: put timeout/retry limit in this loop
                    while (authzState.Status == "pending")
                    {
                        Thread.Sleep(3 * 1000); // this has to be here to give ACME server a chance to think
                        var newAuthzState = client.RefreshIdentifierAuthorization(authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            authzState = newAuthzState;
                        }
                    }

                    authResults.Add(authzState);
                }
                finally
                {
                    if (!string.IsNullOrEmpty(dnsRecordRef))
                    {
                        dnsProvider.RemoveTxtRecord(dnsRecordRef);
                    }
                }
            }

            if (authResults.Any(result => result.Status != "valid"))
            {
                throw new AuthorizationFailedException(authResults);
            }
        }
示例#5
0
        public AuthorizationState HandleVerificationChallenge(TargetApplication application, AuthorizationState authorizationState)
        {
            var challenge     = _acmeClient.DecodeChallenge(authorizationState, AcmeProtocol.CHALLENGE_TYPE_HTTP);
            var httpChallenge = (HttpChallenge)challenge.Challenge;

            if (httpChallenge == null)
            {
                _logger.Error("Could not decode challenge for {hostname} using the {protocol} protocol",
                              authorizationState.Identifier, AcmeProtocol.CHALLENGE_TYPE_HTTP);
                return(null);
            }

            _logger.Information("Expecting response on URL {responseUrl}", httpChallenge.FileUrl);

            CreateChallengeResponse(httpChallenge);
            CheckChallengeResponse(httpChallenge);

            return(_acmeClientService.RequestChallengeVerification(authorizationState, challenge));
        }
        public static async Task <bool> Authorize(AcmeClient client, Account account, List <Domain> ls)
        {
            if (!(account.dnspod_tokens?.Count > 0))
            {
                log.Error("not dnspod token.");
                return(false);
            }
            List <DnspodApiItem> ds = new List <DnspodApiItem>();

            foreach (var token in account.dnspod_tokens)
            {
                var p = await DnspodApiItem.Create(token);

                if (p.domains?.Length > 0)
                {
                    ds.Add(p);
                }
            }
            if (ds.Count == 0)
            {
                log.Error("dnspod token error");
                return(false);
            }

            List <DnspodApiPart> parts = new List <DnspodApiPart>();
            var records = new Dictionary <int, Dnspod.Record.DnspodRecordListResultRecordItem[]>();

            foreach (var d in ls)
            {
                foreach (var a in ds)
                {
                    var found = a.domains.FirstOrDefault(o => o.name.Equals(d.domain, StringComparison.CurrentCultureIgnoreCase) ||
                                                         d.domain.EndsWith($".{o.name}", StringComparison.CurrentCultureIgnoreCase));
                    if (found != null)
                    {
                        var part = new DnspodApiPart()
                        {
                            api = a.api, dns_domain = found, domain = d
                        };
                        if (records.ContainsKey(d.id) == false)
                        {
                            var rr = (await a.api.Record.List(found.id))?.records;
                            records[found.id] = rr;
                            part.records      = rr;
                        }
                        else
                        {
                            part.records = records[found.id];
                        }
                        parts.Add(part);
                        break;
                    }
                }
            }

            foreach (var part in parts)
            {
                log.Info(
                    $"\nAuthorizing Identifier {part.domain.domain} Using Challenge Type {AcmeProtocol.CHALLENGE_TYPE_DNS}");

                part.authzState   = client.AuthorizeIdentifier(part.domain.domain);
                part.challenge    = client.DecodeChallenge(part.authzState, AcmeProtocol.CHALLENGE_TYPE_DNS);
                part.dnsChallenge = part.challenge.Challenge as DnsChallenge;

                // We need to strip off any leading '/' in the path
                var name = part.dnsChallenge.RecordName.Substring(0, part.dnsChallenge.RecordName.Length - 1 - part.dns_domain.name.Length);

                var record = part.records?.FirstOrDefault(o => o.name.ToLower() == name.ToLower());
                if (record == null)
                {
                    var r = await part.api.Record.Create(part.dns_domain.id, name, part.dnsChallenge.RecordValue);

                    part.record_id = r.record.id;
                }
                else
                {
                    var r = await part.api.Record.Modify(part.dns_domain.id, record.id, name, part.dnsChallenge.RecordValue);

                    part.record_id = r.record.id;
                }
            }
            foreach (var part in parts)
            {
                //while (DnspodApi.DnsGetTxtRecord(part.dnsChallenge.RecordName) != part.dnsChallenge.RecordValue)
                //{
                //    Thread.Sleep(10000);
                //}

                log.Info($" Answer should now be browsable at {part.dnsChallenge.RecordName}");

                try
                {
                    log.Info(" Submitting answer");
                    part.authzState.Challenges = new AuthorizeChallenge[] { part.challenge };
                    client.SubmitChallengeAnswer(part.authzState, AcmeProtocol.CHALLENGE_TYPE_DNS, true);

                    // have to loop to wait for server to stop being pending.
                    // TODO: put timeout/retry limit in this loop
                    while (part.authzState.Status == "pending")
                    {
                        log.Info(" Refreshing authorization");
                        Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                        var newAuthzState = client.RefreshIdentifierAuthorization(part.authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            part.authzState = newAuthzState;
                        }
                    }
                    log.Info($" Authorization Result: {part.authzState.Status}");

                    part.domain.AuthorizationState = part.authzState;

                    if (part.authzState.Status == "invalid")
                    {
                        log.Warn($"Authorization Failed {part.authzState.Status}");
                    }
                }
                finally
                {
                }
            }

            return(true);
        }
        private bool AuthorizeBinding(Binding binding)
        {
RetryAfterInvalidAuthorization:             // If LetsEncrypt says a challenge is invalid, and the user hits Y to retry, it'll jump back up here

            if (_AuthorizedIdentifiers.ContainsKey(binding.Hostname))
            {
                return(true);
            }
            else
            {
                Globals.Log();
                Globals.Log($"Authorizing hostname {binding.Hostname} via {AcmeProtocol.CHALLENGE_TYPE_HTTP}");
                Globals.Log(" - Decoding challenge");
                var AuthState     = _Client.AuthorizeIdentifier(binding.Hostname);
                var Challenge     = _Client.DecodeChallenge(AuthState, AcmeProtocol.CHALLENGE_TYPE_HTTP);
                var HttpChallenge = Challenge.Challenge as ACMESharp.ACME.HttpChallenge;

                // Create the challenge file
                var AnswerPath = Environment.ExpandEnvironmentVariables(Path.Combine(binding.WebRootPath, HttpChallenge.FilePath.TrimStart('/')));
                Globals.Log($" - Writing challenge answer to {AnswerPath}");
                Directory.CreateDirectory(Path.GetDirectoryName(AnswerPath));
                File.WriteAllText(AnswerPath, HttpChallenge.FileContent);

                // Create the web.config to allow extensionless file loading
                string WebConfigPath = Path.Combine(Path.GetDirectoryName(AnswerPath), "web.config");
                Globals.Log($" - Copying extensionless-enabling web.config to {WebConfigPath}");
                File.Copy(_Web_ConfigXmlPath, WebConfigPath, true);

                // Warmup the answer url
                Globals.WarmUpUrl(HttpChallenge.FileUrl, HttpChallenge.FileContent);

                try {
                    int x = Console.CursorLeft;
                    int y = Console.CursorTop;

                    Globals.Log(" - Submitting challenge answer");
                    AuthState.Challenges = new AuthorizeChallenge[] { Challenge };
                    _Client.SubmitChallengeAnswer(AuthState, AcmeProtocol.CHALLENGE_TYPE_HTTP, true);

                    // Give a quick 1 second delay before refreshing -- then we'll loop with a "nicer" 5 second delay if we're still pending
                    if (AuthState.Status == "pending")
                    {
                        Thread.Sleep(1000);
                        Globals.Log($" - Checking authorization status");
                        AuthState = _Client.RefreshIdentifierAuthorization(AuthState);
                    }

                    // Loop while in pending state
                    int TryNumber = 2; // 2 because we submitted above, which counts as try #1
                    while (AuthState.Status == "pending")
                    {
                        Globals.Log("   - Authorization pending, waiting 5 seconds before trying again...");
                        Thread.Sleep(5000);

                        // This prevents scrolling while retrying
                        Console.CursorTop -= 1;
                        Console.Write(new string(' ', Console.WindowWidth - 1));
                        Console.SetCursorPosition(x, y);

                        Globals.Log($" - Refreshing authorization status (Try #{TryNumber++})");
                        AuthState = _Client.RefreshIdentifierAuthorization(AuthState);
                    }

                    Globals.Log($" - Authorization status: {AuthState.Status}");
                    if (AuthState.Status == "valid")
                    {
                        // Record the expiry date for the valid result, so we can skip authorization in the future
                        _AuthorizedIdentifiers.Add(binding.Hostname, (DateTime)AuthState.Expires);
                    }
                    else if (AuthState.Status == "invalid")
                    {
                        // Prompt to see if we're going to fix and retry
                        Console.WriteLine("   - LetsEncrypt Uri:");
                        Console.WriteLine($"     {AuthState.Uri}");
                        Console.WriteLine("   - Check the URL above to see if it loads correctly");
                        Console.WriteLine("     If the site does a redirect, it may need to be disabled");
                        Console.WriteLine("     (The LetsEncrypt script contains 'letsencrypt.org' in the user-agent,");
                        Console.WriteLine("      so you could disable rewrite rules for that user-agent fragment)");
                        Console.WriteLine($"     Hit Y to try again or N to skip creating a cert for {binding.IPAddress}");
                        if (Globals.PromptYesNo())
                        {
                            goto RetryAfterInvalidAuthorization;                        // Suck it goto haters
                        }
                        // TODOX Add options for (1) to load challenge url and (2) for LetEncrypt info url
                    }

                    return(AuthState.Status == "valid");
                } finally {
                    // TODOX DeleteAuthorization?
                }
            }
        }
示例#8
0
        public static AuthorizationState Authorize(Target target)
        {
            List <AuthorizationState> authStatus = new List <AuthorizationState>();
            var webRootPath = WebRootPath();
            var directory   = Path.Combine(webRootPath, ".well-known", "acme-challenge");

            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }
            var webConfigPath = Path.Combine(directory, "web.config");

            if (!File.Exists(webConfigPath) || File.ReadAllText(webConfigPath) != webConfig)
            {
                Trace.TraceInformation($"Writing web.config to {webConfigPath}");
                File.WriteAllText(webConfigPath, webConfig);
            }

            foreach (var dnsIdentifier in target.AllDnsIdentifiers)
            {
                //var dnsIdentifier = target.Host;
                Console.WriteLine($"\nAuthorizing Identifier {dnsIdentifier} Using Challenge Type {AcmeProtocol.CHALLENGE_TYPE_HTTP}");
                Trace.TraceInformation("Authorizing Identifier {0} Using Challenge Type {1}", dnsIdentifier, AcmeProtocol.CHALLENGE_TYPE_HTTP);
                var authzState    = client.AuthorizeIdentifier(dnsIdentifier);
                var challenge     = client.DecodeChallenge(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP);
                var httpChallenge = challenge.Challenge as HttpChallenge;

                // We need to strip off any leading '/' in the path
                var filePath = httpChallenge.FilePath;
                if (filePath.StartsWith("/", StringComparison.OrdinalIgnoreCase))
                {
                    filePath = filePath.Substring(1);
                }
                var answerPath = Environment.ExpandEnvironmentVariables(Path.Combine(webRootPath, filePath));

                Console.WriteLine($" Writing challenge answer to {answerPath}");
                Trace.TraceInformation("Writing challenge answer to {0}", answerPath);

                File.WriteAllText(answerPath, httpChallenge.FileContent);

                var answerUri = new Uri(httpChallenge.FileUrl);
                Console.WriteLine($" Answer should now be browsable at {answerUri}");
                Trace.TraceInformation("Answer should now be browsable at {0}", answerUri);

                try
                {
                    var retry = 10;
                    while (true)
                    {
                        using (var handler = new WebRequestHandler())
                        {
                            //Allow self-signed certs otherwise staging wont work
                            handler.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;

                            using (var client = new HttpClient(handler))
                            {
                                Thread.Sleep(1000);
                                var x = client.GetAsync(answerUri).Result;
                                Trace.TraceInformation("Checking status {0}", x.StatusCode);
                                if (x.StatusCode == HttpStatusCode.OK)
                                {
                                    break;
                                }
                                if (retry-- == 0)
                                {
                                    break;
                                }
                                Trace.TraceInformation("Retrying {0}", retry);
                            }
                        }
                    }
                    Console.WriteLine(" Submitting answer");
                    Trace.TraceInformation("Submitting answer");
                    authzState.Challenges = new AuthorizeChallenge[] { challenge };
                    client.SubmitChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP, true);

                    // have to loop to wait for server to stop being pending.
                    retry = 0;
                    while (authzState.Status == "pending" && retry < 6)
                    {
                        retry++;
                        Console.WriteLine(" Refreshing authorization attempt " + retry);
                        Trace.TraceInformation("Refreshing authorization attempt " + retry);
                        Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                        var newAuthzState = client.RefreshIdentifierAuthorization(authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            authzState = newAuthzState;
                        }
                    }

                    Console.WriteLine($" Authorization Result: {authzState.Status}");
                    Trace.TraceInformation("Auth Result {0}", authzState.Status);
                    if (authzState.Status == "invalid")
                    {
                        Trace.TraceError("Authorization Failed {0}", authzState.Status);
                        Trace.TraceInformation("Full Error Details {0}", JsonConvert.SerializeObject(authzState));
                        Console.WriteLine($"The ACME server was probably unable to reach {answerUri}");
                        Trace.TraceError("Unable to reach {0}", answerUri);
                        Console.WriteLine("\nCheck in a browser to see if the answer file is being served correctly.");
                        throw new Exception($"The Lets Encrypt ACME server was probably unable to reach {answerUri} view error report from Lets Encrypt at {authzState.Uri} for more information");
                    }
                    authStatus.Add(authzState);
                }
                finally
                {
                    if (authzState.Status == "valid")
                    {
                        Console.WriteLine(" Deleting answer");
                        Trace.TraceInformation("Deleting answer");
                        File.Delete(answerPath);
                    }
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != "valid")
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = "valid"
            });
        }
示例#9
0
        private List <AuthorizationState> Authorize()
        {
            List <string> allDomains = new List <string>
            {
                this.mainDomain
            };

            allDomains.AddRange(this.alternateNames);

            List <AuthorizationState> authStatus = new List <AuthorizationState>();

            foreach (var domain in allDomains)
            {
                logger.Debug("Authorizing Identifier {0} Using Challenge Type {1}", domain, AcmeProtocol.CHALLENGE_TYPE_HTTP);

                var authState     = client.AuthorizeIdentifier(domain);
                var challenge     = client.DecodeChallenge(authState, AcmeProtocol.CHALLENGE_TYPE_HTTP);
                var httpChallenge = challenge.Challenge as HttpChallenge;

                // We need to strip off any leading '/' in the path
                var filePath = httpChallenge.FilePath;
                if (filePath.StartsWith("/", StringComparison.OrdinalIgnoreCase))
                {
                    filePath = filePath.Substring(1);
                }
                var answerPath = Path.Combine(this.websitePath, filePath);

                logger.Debug("Writing challenge answer to {0}", answerPath);

                var directory = Path.GetDirectoryName(answerPath);
                Directory.CreateDirectory(directory);
                File.WriteAllText(answerPath, httpChallenge.FileContent);

                var answerUri = new Uri(httpChallenge.FileUrl);

                logger.Debug("Answer should now be browsable at {0}", answerUri);

                logger.Debug("Submitting answer");

                authState.Challenges = new AuthorizeChallenge[] { challenge };
                client.SubmitChallengeAnswer(authState, AcmeProtocol.CHALLENGE_TYPE_HTTP, true);

                // have to loop to wait for server to stop being pending.
                // TODO: put timeout/retry limit in this loop
                int timeout = 10;
                while (authState.Status == "pending" && timeout > 0)
                {
                    logger.Debug("Refreshing authorization");
                    Thread.Sleep(2000);
                    var newAuthzState = client.RefreshIdentifierAuthorization(authState);

                    if (newAuthzState.Status != "pending")
                    {
                        authState = newAuthzState;
                    }

                    timeout--;
                }

                if (timeout == 0)
                {
                    logger.Error("Timeout waiting for {0}", domain);
                    authStatus.Add(authState);

                    return(authStatus);
                }

                logger.Debug("Authorization Result: {0}", authState.Status);

                if (authState.Status == "invalid")
                {
                    logger.Error("Authorization Failed {0}", authState.Status);
                    logger.Error("Full Error Details {0}", authState);
                    logger.Error("The ACME server was probably unable to reach {0}", answerUri);
                }

                authStatus.Add(authState);
            }

            return(authStatus);
        }
示例#10
0
        public static AuthorizationState Authorize(Target target)
        {
            List <string>             identifiers = target.GetHosts(false);
            List <AuthorizationState> authStatus  = new List <AuthorizationState>();

            foreach (var identifier in identifiers)
            {
                var authzState = _client.AuthorizeIdentifier(identifier);
                if (authzState.Status == "valid" && !_options.Test)
                {
                    _log.Information("Cached authorization result: {Status}", authzState.Status);
                    authStatus.Add(authzState);
                }
                else
                {
                    var validation = target.GetValidationPlugin();
                    if (validation == null)
                    {
                        return(new AuthorizationState {
                            Status = "invalid"
                        });
                    }
                    _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})", identifier, validation.ChallengeType, validation.Name);
                    var challenge = _client.DecodeChallenge(authzState, validation.ChallengeType);
                    var cleanUp   = validation.PrepareChallenge(target, challenge, identifier, _options, _input);

                    try
                    {
                        _log.Debug("Submitting answer");
                        authzState.Challenges = new AuthorizeChallenge[] { challenge };
                        _client.SubmitChallengeAnswer(authzState, validation.ChallengeType, true);

                        // have to loop to wait for server to stop being pending.
                        // TODO: put timeout/retry limit in this loop
                        while (authzState.Status == "pending")
                        {
                            _log.Debug("Refreshing authorization");
                            Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                            var newAuthzState = _client.RefreshIdentifierAuthorization(authzState);
                            if (newAuthzState.Status != "pending")
                            {
                                authzState = newAuthzState;
                            }
                        }

                        _log.Information("Authorization result: {Status}", authzState.Status);
                        authStatus.Add(authzState);
                    }
                    finally
                    {
                        cleanUp(authzState);
                    }
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != "valid")
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = "valid"
            });
        }
示例#11
0
        public static AuthorizationState Authorize(Target target)
        {
            List <string> identifiers = new List <string>();

            if (!Options.San)
            {
                identifiers.Add(target.Host);
            }
            identifiers.AddRange(target.AlternativeNames);
            identifiers = identifiers.Where(x => !string.IsNullOrWhiteSpace(x)).Distinct().ToList();
            if (identifiers.Count() == 0)
            {
                Log.Error("No DNS identifiers found.");
                throw new Exception("No DNS identifiers found.");
            }
            List <AuthorizationState> authStatus = new List <AuthorizationState>();

            foreach (var dnsIdentifier in identifiers)
            {
                string answerUri;
                var    challengeType = target.Plugin.ChallengeType;

                Log.Information("Authorizing Identifier {dnsIdentifier} Using Challenge Type {challengeType}", dnsIdentifier, challengeType);
                var authzState = _client.AuthorizeIdentifier(dnsIdentifier);
                var challenge  = _client.DecodeChallenge(authzState, challengeType);
                var cleanUp    = challengeType == AcmeProtocol.CHALLENGE_TYPE_HTTP
                              ? PrepareHttpChallenge(target, challenge, out answerUri)
                              : PrepareDnsChallenge(target, challenge, out answerUri);

                try
                {
                    Log.Information("Submitting answer");
                    authzState.Challenges = new AuthorizeChallenge[] { challenge };
                    _client.SubmitChallengeAnswer(authzState, challengeType, true);

                    // have to loop to wait for server to stop being pending.
                    // TODO: put timeout/retry limit in this loop
                    while (authzState.Status == "pending")
                    {
                        Log.Information("Refreshing authorization");
                        Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                        var newAuthzState = _client.RefreshIdentifierAuthorization(authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            authzState = newAuthzState;
                        }
                    }

                    Log.Information("Authorization Result: {Status}", authzState.Status);
                    if (authzState.Status == "invalid")
                    {
                        Log.Error("Authorization Failed {Status}", authzState.Status);
                        Log.Debug("Full Error Details {@authzState}", authzState);
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("\n******************************************************************************");
                        Log.Error("The ACME server was probably unable to reach {answerUri}", answerUri);
                        Console.WriteLine("\nCheck in a browser to see if the answer file is being served correctly. If it is, also check the DNSSEC configuration.");

                        target.Plugin.OnAuthorizeFail(target);

                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("\n******************************************************************************");
                        Console.ResetColor();
                    }
                    authStatus.Add(authzState);
                }
                finally
                {
                    cleanUp(authzState);
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != "valid")
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = "valid"
            });
        }
示例#12
0
        public static AuthorizationState Authorize(Target target)
        {
            List <string> dnsIdentifiers = new List <string>();

            if (!Options.SAN)
            {
                dnsIdentifiers.Add(target.Host);
            }
            if (target.AlternativeNames != null)
            {
                dnsIdentifiers.AddRange(target.AlternativeNames);
            }
            List <AuthorizationState> authStatus = new List <AuthorizationState>();

            foreach (var dnsIdentifier in dnsIdentifiers)
            {
                //var dnsIdentifier = target.Host;
                var webRootPath = target.WebRootPath;

                Console.WriteLine($"\nAuthorizing Identifier {dnsIdentifier} Using Challenge Type {AcmeProtocol.CHALLENGE_TYPE_HTTP}");
                Log.Information("Authorizing Identifier {dnsIdentifier} Using Challenge Type {CHALLENGE_TYPE_HTTP}", dnsIdentifier, AcmeProtocol.CHALLENGE_TYPE_HTTP);
                var authzState    = client.AuthorizeIdentifier(dnsIdentifier);
                var challenge     = client.DecodeChallenge(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP);
                var httpChallenge = challenge.Challenge as HttpChallenge;

                // We need to strip off any leading '/' in the path
                var filePath = httpChallenge.FilePath;
                if (filePath.StartsWith("/", StringComparison.OrdinalIgnoreCase))
                {
                    filePath = filePath.Substring(1);
                }
                var answerPath = Environment.ExpandEnvironmentVariables(Path.Combine(webRootPath, filePath));

                Console.WriteLine($" Writing challenge answer to {answerPath}");
                Log.Information("Writing challenge answer to {answerPath}", answerPath);
                var directory = Path.GetDirectoryName(answerPath);
                Directory.CreateDirectory(directory);
                File.WriteAllText(answerPath, httpChallenge.FileContent);

                target.Plugin.BeforeAuthorize(target, answerPath);

                var answerUri = new Uri(httpChallenge.FileUrl);
                Console.WriteLine($" Answer should now be browsable at {answerUri}");
                Log.Information("Answer should now be browsable at {answerUri}", answerUri);

                try
                {
                    Console.WriteLine(" Submitting answer");
                    Log.Information("Submitting answer");
                    authzState.Challenges = new AuthorizeChallenge[] { challenge };
                    client.SubmitChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP, true);

                    // have to loop to wait for server to stop being pending.
                    // TODO: put timeout/retry limit in this loop
                    while (authzState.Status == "pending")
                    {
                        Console.WriteLine(" Refreshing authorization");
                        Log.Information("Refreshing authorization");
                        Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                        var newAuthzState = client.RefreshIdentifierAuthorization(authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            authzState = newAuthzState;
                        }
                    }

                    Console.WriteLine($" Authorization Result: {authzState.Status}");
                    Log.Information("Auth Result {Status}", authzState.Status);
                    if (authzState.Status == "invalid")
                    {
                        Log.Error("Authorization Failed {Status}", authzState.Status);
                        Log.Debug("Full Error Details {@authzState}", authzState);
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("\n******************************************************************************");
                        Console.WriteLine($"The ACME server was probably unable to reach {answerUri}");
                        Log.Error("Unable to reach {answerUri}", answerUri);

                        Console.WriteLine("\nCheck in a browser to see if the answer file is being served correctly.");

                        target.Plugin.OnAuthorizeFail(target);

                        Console.WriteLine("\n******************************************************************************");
                        Console.ResetColor();
                    }
                    authStatus.Add(authzState);
                }
                finally
                {
                    if (authzState.Status == "valid")
                    {
                        Console.WriteLine(" Deleting answer");
                        Log.Information("Deleting answer");
                        File.Delete(answerPath);
                    }
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != "valid")
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = "valid"
            });
        }
示例#13
0
        public async Task <AuthorizationState> Authorize(AcmeClient client, List <string> allDnsIdentifiers)
        {
            List <AuthorizationState> authStatus = new List <AuthorizationState>();

            foreach (var dnsIdentifier in allDnsIdentifiers)
            {
                //var dnsIdentifier = target.Host;
                Console.WriteLine($"\nAuthorizing Identifier {dnsIdentifier} Using Challenge Type {AcmeProtocol.CHALLENGE_TYPE_DNS}");
                Trace.TraceInformation("Authorizing Identifier {0} Using Challenge Type {1}", dnsIdentifier, AcmeProtocol.CHALLENGE_TYPE_DNS);
                var authzState   = client.AuthorizeIdentifier(dnsIdentifier);
                var challenge    = client.DecodeChallenge(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS);
                var dnsChallenge = challenge.Challenge as DnsChallenge;

                await PersistsChallenge(dnsChallenge);

                var answerUri = new Uri(dnsChallenge.RecordValue);
                Console.WriteLine($" DNS Answer should now be available as {dnsChallenge.RecordName} with value {answerUri}");
                Trace.TraceInformation($" DNS Answer should now be available as {dnsChallenge.RecordName} with value {answerUri}");

                try
                {
                    var retry = 10;
                    //var handler = new WebRequestHandler();
                    //handler.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;

                    //var httpclient = new HttpClient(handler);
                    //while (true)
                    //{

                    //    //Allow self-signed certs otherwise staging wont work


                    //    await Task.Delay(1000);
                    //    var x = await httpclient.GetAsync(answerUri);
                    //    Trace.TraceInformation("Checking status {0}", x.StatusCode);
                    //    if (x.StatusCode == HttpStatusCode.OK)
                    //        break;
                    //    if (retry-- == 0)
                    //        break;
                    //    Trace.TraceInformation("Retrying {0}", retry);
                    //}
                    Console.WriteLine(" Submitting answer");
                    Trace.TraceInformation("Submitting answer");
                    authzState.Challenges = new AuthorizeChallenge[] { challenge };
                    client.SubmitChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS, true);

                    // have to loop to wait for server to stop being pending.
                    retry = 0;
                    while (authzState.Status == "pending" && retry < 6)
                    {
                        retry++;
                        Console.WriteLine(" Refreshing authorization attempt " + retry);
                        Trace.TraceInformation("Refreshing authorization attempt " + retry);
                        await Task.Delay(2000 *retry);  // this has to be here to give ACME server a chance to think

                        var newAuthzState = client.RefreshIdentifierAuthorization(authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            authzState = newAuthzState;
                        }
                    }

                    Console.WriteLine($" Authorization Result: {authzState.Status}");
                    Trace.TraceInformation("Auth Result {0}", authzState.Status);
                    if (authzState.Status == "invalid" || authzState.Status == "pending")
                    {
                        Trace.TraceError("Authorization Failed {0}", authzState.Status);
                        Trace.TraceInformation("Full Error Details {0}", JsonConvert.SerializeObject(authzState));
                        Console.WriteLine($"The ACME server was probably unable to reach {answerUri}");
                        Trace.TraceError("Unable to reach {0}", answerUri);
                        Console.WriteLine("\nCheck in a browser to see if the answer file is being served correctly.");
                        throw new Exception($"The Lets Encrypt ACME server was probably unable to reach {answerUri} view error report from Lets Encrypt at {authzState.Uri} for more information");
                    }
                    authStatus.Add(authzState);
                }
                finally
                {
                    if (authzState.Status == "valid")
                    {
                        Console.WriteLine(" Deleting answer");
                        Trace.TraceInformation("Deleting answer");
                        await CleanupChallenge(dnsChallenge);
                    }
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != "valid")
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = "valid"
            });
        }
示例#14
0
        public async Task <AuthorizationState> Authorize(AcmeClient client, List <string> allDnsIdentifiers)
        {
            List <AuthorizationState> authStatus = new List <AuthorizationState>();

            foreach (var dnsIdentifier in allDnsIdentifiers)
            {
                Trace.TraceInformation("Authorizing Identifier {0} Using Challenge Type {1}", dnsIdentifier, AcmeProtocol.CHALLENGE_TYPE_DNS);
                var authzState   = client.AuthorizeIdentifier(dnsIdentifier);
                var challenge    = client.DecodeChallenge(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS);
                var dnsChallenge = challenge.Challenge as DnsChallenge;

                await PersistsChallenge(dnsChallenge);

                Trace.TraceInformation($" DNS Answer should now be available as {dnsChallenge.RecordName} with value {dnsChallenge.RecordValue}");

                try
                {
                    var retry = 10;
                    Trace.TraceInformation("Submitting answer");
                    authzState.Challenges = new AuthorizeChallenge[] { challenge };
                    client.SubmitChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_DNS, true);

                    // have to loop to wait for server to stop being pending.
                    retry = 0;
                    while (authzState.Status == "pending" && retry < 6)
                    {
                        retry++;
                        Trace.TraceInformation("Refreshing authorization attempt " + retry);
                        await Task.Delay(2000 *retry);  // this has to be here to give ACME server a chance to think

                        var newAuthzState = client.RefreshIdentifierAuthorization(authzState);
                        if (newAuthzState.Status != "pending")
                        {
                            authzState = newAuthzState;
                        }
                    }

                    Trace.TraceInformation("Auth Result {0}", authzState.Status);
                    if (authzState.Status == "invalid" || authzState.Status == "pending")
                    {
                        Trace.TraceError("Authorization Failed {0}", authzState.Status);
                        Trace.TraceInformation("Full Error Details {0}", JsonConvert.SerializeObject(authzState));
                        Trace.TraceError("Unable to find TXT record {0}", dnsChallenge.RecordValue);
                        throw new Exception($"The Lets Encrypt ACME server was probably unable to find TXT record with value {dnsChallenge.RecordValue} view error report from Lets Encrypt at {authzState.Uri} for more information");
                    }
                    authStatus.Add(authzState);
                }
                finally
                {
                    if (authzState.Status == "valid")
                    {
                        Console.WriteLine(" Deleting answer");
                        Trace.TraceInformation("Deleting answer");
                        await CleanupChallenge(dnsChallenge);
                    }
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != "valid")
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = "valid"
            });
        }
示例#15
0
        public static AuthorizationState Authorize(Target target)
        {
            var dnsIdentifier = target.Host;
            var webRootPath   = target.WebRootPath;

            Console.WriteLine($"\nAuthorizing Identifier {dnsIdentifier} Using Challenge Type {AcmeProtocol.CHALLENGE_TYPE_HTTP}");
            var authzState    = client.AuthorizeIdentifier(dnsIdentifier);
            var challenge     = client.DecodeChallenge(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP);
            var httpChallenge = challenge.Challenge as HttpChallenge;

            // We need to strip off any leading '/' in the path
            var filePath = httpChallenge.FilePath;

            if (filePath.StartsWith("/", StringComparison.OrdinalIgnoreCase))
            {
                filePath = filePath.Substring(1);
            }
            var answerPath = Environment.ExpandEnvironmentVariables(Path.Combine(webRootPath, filePath));

            Console.WriteLine($" Writing challenge answer to {answerPath}");
            var directory = Path.GetDirectoryName(answerPath);

            Directory.CreateDirectory(directory);
            File.WriteAllText(answerPath, httpChallenge.FileContent);

            target.Plugin.BeforeAuthorize(target, answerPath);

            var answerUri = new Uri(httpChallenge.FileUrl);

            Console.WriteLine($" Answer should now be browsable at {answerUri}");

            try
            {
                Console.WriteLine(" Submitting answer");
                authzState.Challenges = new AuthorizeChallenge[] { challenge };
                client.SubmitChallengeAnswer(authzState, AcmeProtocol.CHALLENGE_TYPE_HTTP, true);

                // have to loop to wait for server to stop being pending.
                // TODO: put timeout/retry limit in this loop
                while (authzState.Status == "pending")
                {
                    Console.WriteLine(" Refreshing authorization");
                    Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                    var newAuthzState = client.RefreshIdentifierAuthorization(authzState);
                    if (newAuthzState.Status != "pending")
                    {
                        authzState = newAuthzState;
                    }
                }

                Console.WriteLine($" Authorization Result: {authzState.Status}");
                if (authzState.Status == "invalid")
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("\n******************************************************************************");
                    Console.WriteLine($"The ACME server was probably unable to reach {answerUri}");

                    Console.WriteLine("\nCheck in a browser to see if the answer file is being served correctly.");

                    target.Plugin.OnAuthorizeFail(target);

                    Console.WriteLine("\n******************************************************************************");
                    Console.ResetColor();
                }

                //if (authzState.Status == "valid")
                //{
                //    var authPath = Path.Combine(configPath, dnsIdentifier + ".auth");
                //    Console.WriteLine($" Saving authorization record to: {authPath}");
                //    using (var authStream = File.Create(authPath))
                //        authzState.Save(authStream);
                //}

                return(authzState);
            }
            finally
            {
                if (authzState.Status == "valid")
                {
                    Console.WriteLine(" Deleting answer");
                    File.Delete(answerPath);
                }
            }
        }