Пример #1
0
    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),
            )
Пример #2
0
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],
    )
Пример #3
0
 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)))
         )
Пример #4
0
 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)
Пример #5
0
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.')
Пример #6
0
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
Пример #7
0
 def _create_client(self, key):
     return Client.from_url(reactor, LETSENCRYPT_STAGING_DIRECTORY, key=key)
Пример #8
0
    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()
Пример #9
0
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.')
Пример #10
0
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