def test_challenge_unexpected_uri(self): """ ``_check_challenge`` raises `~acme.errors.UnexpectedUpdate` if the challenge does not have the expected URI. """ # Crazy dance that was used in previous test. url1 = URL.fromText(u'https://example.org/').asURI().asText() url2 = URL.fromText(u'https://example.com/').asURI().asText() with self.assertRaises(errors.UnexpectedUpdate): Client._check_challenge( challenge=messages.ChallengeResource( body=messages.ChallengeBody(chall=None, uri=url1)), challenge_body=messages.ChallengeBody(chall=None, uri=url2), )
def create_issuing_service( reactor: IReactorTCP, acme_url: str, account_key_file: str, well_known_resource: IResource, ) -> AcmeIssuingService: """Create an ACME issuing service, and attach it to a web Resource Args: reactor: twisted reactor acme_url: URL to use to request certificates account_key_file: where to store the account key well_known_resource: web resource for .well-known. we will attach a child resource for "acme-challenge". Returns: AcmeIssuingService """ responder = HTTP01Responder() well_known_resource.putChild(b"acme-challenge", responder.resource) store = ErsatzStore() return AcmeIssuingService( cert_store=store, client_creator=(lambda: Client.from_url( reactor=reactor, url=URL.from_text(acme_url), key=load_or_create_client_key(account_key_file), alg=RS256, )), clock=reactor, responders=[responder], )
def _create_client(self, key): return ( Client.from_url(reactor, LETSENCRYPT_STAGING_DIRECTORY, key=key) .addCallback(tap( lambda client: self.addCleanup( client._client._treq._agent._pool.closeCachedConnections))) )
def test_directory_url_type(self): """ `~txacme.client.Client.from_url` expects a ``twisted.python.url.URL`` instance for the ``url`` argument. """ with self.assertRaises(TypeError): yield Client.from_url(reactor, '/wrong/kind/of/directory', key=RSA_KEY_512)
def get_things_done(): """ Here is where the service part is setup and action is done. """ responders = yield start_responders() store = MemoryStore() # We first validate the directory. account_key = _get_account_key() try: client = yield Client.from_url( reactor, URL.fromText(acme_url.decode('utf-8')), key=JWKRSA(key=account_key), alg=RS256, ) except Exception as error: print('\n\nFailed to connect to ACME directory. %s' % (error, )) yield reactor.stop() defer.returnValue(None) service = AcmeIssuingService( email='[email protected],[email protected]', cert_store=store, client=client, clock=reactor, responders=responders, panic=on_panic, ) # Start the service and wait for it to start. yield service.start() # Wait for the existing certificate from the storage to be available. yield service.when_certs_valid() # Request a SAN ... if passed via command line. yield service.issue_cert(','.join(requested_domains)) yield service.stopService() print('That was all the example.')
def makeService(config): ini = ConfigParser.RawConfigParser() ini.read(config['config']) configPath = FilePath(config['config']).parent() rproxyConf = dict(ini.items("rproxy")) hostsConf = dict(ini.items("hosts")) hosts = {} for k, v in hostsConf.items(): k = k.lower() hostname, part = k.rsplit("_", 1) if hostname not in hosts: hosts[hostname] = {} hosts[hostname][part] = v if not hosts: raise ValueError("No hosts configured.") for i in hosts: if "port" not in hosts[i]: raise ValueError("All hosts need a port.") if "host" not in hosts[i]: print("%s does not have a host, making localhost" % (i,)) hosts[i]["host"] = "localhost" if "wwwtoo" not in hosts[i]: print("%s does not have an wwwtoo setting, making True" % (i,)) hosts[i]["wwwtoo"] = "True" if "proxysecure" not in hosts[i]: print("%s does not have an proxysecure setting, making False" % (i,)) hosts[i]["proxysecure"] = False hosts[i]["wwwtoo"] = True if hosts[i]["wwwtoo"]=="True" else False hosts[i]["proxysecure"] = True if hosts[i]["proxysecure"]=="True" else False hosts[i]["sendhsts"] = True if hosts[i].get("sendhsts")=="True" else False from twisted.internet import reactor pool = HTTPConnectionPool(reactor) resource = EncodingResourceWrapper( RProxyResource(hosts, rproxyConf.get("clacks"), pool, reactor, {}, False), [server.GzipEncoderFactory()]) responder = HTTP01Responder() site = server.Site(EnsureHTTPS(resource, responder.resource),) multiService = service.MultiService() certificates = rproxyConf.get("certificates", None) if certificates: try: configPath.child(certificates).makedirs() except: pass certificates = configPath.child(certificates).path for i in rproxyConf.get("https_ports").split(","): print("Starting HTTPS on port " + i) multiService.addService(strports.service('txsni:' + certificates + ':tcp:' + i, site)) for host in hosts.keys(): with open(FilePath(certificates).child(host + ".pem").path, 'r+'): # Open it so that txacme can find it pass if hosts[host]["wwwtoo"]: with open(FilePath(certificates).child("www." + host + ".pem").path, 'r+'): # Open it so that txacme can find it pass for i in rproxyConf.get("http_ports", "").split(","): print("Starting HTTP on port " + i) multiService.addService(strports.service('tcp:' + i, site)) issuingService = AcmeIssuingService( cert_store=DirectoryStore(FilePath(certificates)), client_creator=(lambda: Client.from_url( reactor=reactor, url=LETSENCRYPT_DIRECTORY, key=load_or_create_client_key(FilePath(certificates)), alg=RS256, )), clock=reactor, responders=[responder], ) issuingService.setServiceParent(multiService) return multiService
def _create_client(self, key): return Client.from_url(reactor, LETSENCRYPT_STAGING_DIRECTORY, key=key)
def start_listening(self): # Configure logging for txacme, if you need to debug # from eliot import add_destinations # from eliot.twisted import TwistedDestination # # add_destinations(TwistedDestination()) from txacme.challenges import HTTP01Responder from txacme.service import AcmeIssuingService from txacme.endpoint import load_or_create_client_key from txacme.client import Client from josepy.jwa import RS256 self._store = ErsatzStore() responder = HTTP01Responder() self._issuer = AcmeIssuingService( cert_store=self._store, client_creator=(lambda: Client.from_url( reactor=self.reactor, url=URL.from_text(self.hs.config.acme_url), key=load_or_create_client_key( FilePath(self.hs.config.config_dir_path)), alg=RS256, )), clock=self.reactor, responders=[responder], ) well_known = Resource() well_known.putChild(b'acme-challenge', responder.resource) responder_resource = Resource() responder_resource.putChild(b'.well-known', well_known) responder_resource.putChild(b'check', static.Data(b'OK', b'text/plain')) srv = server.Site(responder_resource) bind_addresses = self.hs.config.acme_bind_addresses for host in bind_addresses: logger.info( "Listening for ACME requests on %s:%i", host, self.hs.config.acme_port, ) try: self.reactor.listenTCP( self.hs.config.acme_port, srv, interface=host, ) except twisted.internet.error.CannotListenError as e: check_bind_error(e, host, bind_addresses) # Make sure we are registered to the ACME server. There's no public API # for this, it is usually triggered by startService, but since we don't # want it to control where we save the certificates, we have to reach in # and trigger the registration machinery ourselves. self._issuer._registered = False yield self._issuer._ensure_registered()
def get_things_done(): """ Here is where the client part is setup and action is done. """ responders = yield start_responders() # We first validate the directory. account_key = _get_account_key() try: client = yield Client.from_url( reactor, URL.fromText(acme_url.decode('utf-8')), key=JWKRSA(key=account_key), alg=RS256, ) except Exception as error: print('\n\nFailed to connect to ACME directory. %s' % (error, )) yield reactor.stop() defer.returnValue(None) # Then we register a new account or update an existing account. # First register a new account with a contact set, then using the same # key call register with a different contact and see that it was updated. response = yield client.start( email='[email protected],[email protected]') print('Account URI: %s' % (response.uri, )) print('Account contact: %s' % (response.body.contact, )) # We request a single certificate for a list of domains and get an "order" cert_key = generate_private_key('rsa') orderr = yield client.submit_order(cert_key, requested_domains) # Each order had a list of "authorizations" for which the challenge needs # to be validated. for authorization in orderr.authorizations: try: # Make sure all ACME server requests are sequential. # For now, answering to the challenges in parallel will not work. yield answer_challenge(authorization, client, responders, clock=reactor) except Exception as error: print('\n\nFailed to validate a challenge. %s' % (error, )) yield reactor.stop() defer.returnValue(None) certificate = yield get_certificate(orderr, client, clock=reactor) print('Got a new cert:\n') print(certificate.body) cert_key_pem = cert_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) # Cleanup the client and disconnect any persistent connection to the # ACME server. yield client.stop() # The new certificate is available and we can start a demo HTTPS server # using it. yield start_https_demo_server(cert_key_pem, certificate.body) print('txacme demo done.')
def makeService(config): ini = ConfigParser.RawConfigParser() ini.read(config['config']) configPath = FilePath(config['config']).parent() rproxyConf = dict(ini.items("rproxy")) hostsConf = dict(ini.items("hosts")) hosts = {} for k, v in hostsConf.items(): k = k.lower() hostname, part = k.rsplit("_", 1) if hostname not in hosts: hosts[hostname] = {} hosts[hostname][part] = v if not hosts: raise ValueError("No hosts configured.") for i in hosts: if "port" not in hosts[i]: raise ValueError("All hosts need a port.") if "host" not in hosts[i]: print("%s does not have a host, making localhost" % (i, )) hosts[i]["host"] = "localhost" if "wwwtoo" not in hosts[i]: print("%s does not have an wwwtoo setting, making True" % (i, )) hosts[i]["wwwtoo"] = "True" if "proxysecure" not in hosts[i]: print("%s does not have an proxysecure setting, making False" % (i, )) hosts[i]["proxysecure"] = False hosts[i]["wwwtoo"] = True if hosts[i]["wwwtoo"] == "True" else False hosts[i]["proxysecure"] = True if hosts[i][ "proxysecure"] == "True" else False hosts[i]["sendhsts"] = True if hosts[i].get( "sendhsts") == "True" else False from twisted.internet import reactor pool = HTTPConnectionPool(reactor) resource = EncodingResourceWrapper( RProxyResource(hosts, rproxyConf.get("clacks"), pool, reactor, {}, False), [server.GzipEncoderFactory()]) responder = HTTP01Responder() site = server.Site(EnsureHTTPS(resource, responder.resource), ) multiService = service.MultiService() certificates = rproxyConf.get("certificates", None) if certificates: try: configPath.child(certificates).makedirs() except: pass certificates = configPath.child(certificates).path for i in rproxyConf.get("https_ports").split(","): print("Starting HTTPS on port " + i) multiService.addService( strports.service('txsni:' + certificates + ':tcp:' + i, site)) for host in hosts.keys(): with open(FilePath(certificates).child(host + ".pem").path, 'w'): # Open it so that txacme can find it pass if hosts[host]["wwwtoo"]: with open( FilePath(certificates).child("www." + host + ".pem").path, 'w'): # Open it so that txacme can find it pass for i in rproxyConf.get("http_ports", "").split(","): print("Starting HTTP on port " + i) multiService.addService(strports.service('tcp:' + i, site)) issuingService = AcmeIssuingService( cert_store=DirectoryStore(FilePath(certificates)), client_creator=(lambda: Client.from_url( reactor=reactor, url=LETSENCRYPT_DIRECTORY, key=load_or_create_client_key(FilePath(certificates)), alg=RS256, )), clock=reactor, responders=[responder], ) issuingService.setServiceParent(multiService) return multiService