def test_interface(self): """ The `.IResponder` interface is correctly implemented. """ responder = HTTP01Responder() verifyObject(IResponder, responder) self.assertEqual(u'http-01', responder.challenge_type)
def __init__(self, marathon_client, group, cert_store, mlb_client, txacme_client_creator, reactor, email=None): """ Create the marathon-acme service. :param marathon_client: The Marathon API client. :param group: The name of the marathon-lb group. :param cert_store: The ``ICertificateStore`` instance to use. :param mlb_clinet: The marathon-lb API client. :param txacme_client_creator: Callable to create the txacme client. :param reactor: The reactor to use. :param email: The ACME registration email. """ self.marathon_client = marathon_client self.group = group self.reactor = reactor responder = HTTP01Responder() self.server = MarathonAcmeServer(responder.resource) mlb_cert_store = MlbCertificateStore(cert_store, mlb_client) self.txacme_service = AcmeIssuingService(mlb_cert_store, txacme_client_creator, reactor, [responder], email) self._server_listening = None
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 test_stop_responding_already_stopped(self): """ Calling ``stop_responding`` when we are not responding for a server name does nothing. """ token = EXAMPLE_TOKEN challenge = challenges.HTTP01(token=token) response = challenge.response(RSA_KEY_512) responder = HTTP01Responder() yield responder.stop_responding(u'example.com', challenge, response)
def test_start_responding(self, token): """ Calling ``start_responding`` makes an appropriate resource available. """ challenge = challenges.HTTP01(token=token) response = challenge.response(RSA_KEY_512) responder = HTTP01Responder() challenge_resource = Resource() challenge_resource.putChild(b'acme-challenge', responder.resource) root = Resource() root.putChild(b'.well-known', challenge_resource) client = StubTreq(root) encoded_token = challenge.encode('token') challenge_url = URL( host=u'example.com', path=[u'.well-known', u'acme-challenge', encoded_token]).asText() self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(404)))) responder.start_responding(u'example.com', challenge, response) self.assertThat( client.get(challenge_url), succeeded( MatchesAll( MatchesStructure(code=Equals(200), headers=AfterPreprocessing( methodcaller('getRawHeaders', b'content-type'), Equals([b'text/plain']))), AfterPreprocessing( methodcaller('content'), succeeded( Equals(response.key_authorization.encode( 'utf-8'))))))) # Starting twice before stopping doesn't break things responder.start_responding(u'example.com', challenge, response) self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(200)))) responder.stop_responding(u'example.com', challenge, response) self.assertThat(client.get(challenge_url), succeeded(MatchesStructure(code=Equals(404))))
def test_start_responding(self): """ Calling ``start_responding`` makes an appropriate resource available. """ token = b'BWYcfxzmOha7-7LoxziqPZIUr99BCz3BfbN9kzSFnrU' challenge = challenges.HTTP01(token=token) response = challenge.response(RSA_KEY_512) responder = HTTP01Responder() challenge_resource = Resource() challenge_resource.putChild(b'acme-challenge', responder.resource) root = Resource() root.putChild(b'.well-known', challenge_resource) client = StubTreq(root) encoded_token = challenge.encode('token') challenge_url = URL( host=u'example.com', path=[u'.well-known', u'acme-challenge', encoded_token]).asText() # We got page not found while the challenge is not yet active. result = yield client.get(challenge_url) self.assertEqual(404, result.code) # Once we enable the response. responder.start_responding(u'example.com', challenge, response) result = yield client.get(challenge_url) self.assertEqual(200, result.code) self.assertEqual(['text/plain'], result.headers.getRawHeaders('content-type')) result = yield result.content() self.assertEqual(response.key_authorization.encode('utf-8'), result) # Starting twice before stopping doesn't break things responder.start_responding(u'example.com', challenge, response) result = yield client.get(challenge_url) self.assertEqual(200, result.code) yield responder.stop_responding(u'example.com', challenge, response) result = yield client.get(challenge_url) self.assertEqual(404, result.code)
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 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