예제 #1
0
 def _test_registration(self):
     return (
         DeferredContext(self._test_create_client())
         .addCallback(partial(setattr, self, 'client'))
         .addCallback(lambda _: self._test_register())
         .addCallback(tap(
             lambda reg1: self.assertEqual(reg1.body.contact, ())))
         .addCallback(tap(
             lambda reg1:
             self._test_register(
                 NewRegistration.from_data(email=u'*****@*****.**'))
             .addCallback(tap(
                 lambda reg2: self.assertEqual(reg1.uri, reg2.uri)))
             .addCallback(lambda reg2: self.assertEqual(
                 reg2.body.contact, (u'mailto:[email protected]',)))))
         .addCallback(self._test_agree_to_tos)
         .addCallback(
             lambda _: self._test_request_challenges(self.HOST))
         .addCallback(partial(setattr, self, 'authzr'))
         .addCallback(lambda _: self._create_responder())
         .addCallback(tap(lambda _: self._test_poll_pending(self.authzr)))
         .addCallback(self._test_answer_challenge)
         .addCallback(tap(lambda _: self._test_poll(self.authzr)))
         .addCallback(lambda stop_responding: stop_responding())
         .addCallback(lambda _: self._test_issue(self.HOST))
         .addCallback(self._test_chain)
         .addActionFinish())
예제 #2
0
 def poll(self, authzr):
     """
     Update an authorization from the server (usually to check its status).
     """
     action = LOG_ACME_POLL_AUTHORIZATION(authorization=authzr)
     with action.context():
         return (
             DeferredContext(self._client.get(authzr.uri))
             # Spec says we should get 202 while pending, Boulder actually
             # sends us 200 always, so just don't check.
             # .addCallback(self._expect_response, http.ACCEPTED)
             .addCallback(
                 lambda res:
                 self._parse_authorization(res, uri=authzr.uri)
                 .addCallback(
                     self._check_authorization, authzr.body.identifier)
                 .addCallback(
                     lambda authzr:
                     (authzr,
                      self.retry_after(res, _now=self._clock.seconds)))
             )
             .addCallback(tap(
                 lambda a_r: action.add_success_fields(
                     authorization=a_r[0], retry_after=a_r[1])))
             .addActionFinish())
예제 #3
0
파일: client.py 프로젝트: twisted/txacme
    def _send_request(self, method, url, *args, **kwargs):
        """
        Send HTTP request.

        :param str method: The HTTP method to use.
        :param str url: The URL to make the request to.

        :return: Deferred firing with the HTTP response.
        """
        if self._current_request is not None:
            return defer.fail(RuntimeError('Overlapped HTTP request'))

        def cb_request_done(result):
            """
            Called when we got a response from the request.
            """
            self._current_request = None
            return result

        action = LOG_JWS_REQUEST(url=url)
        with action.context():
            headers = kwargs.setdefault('headers', Headers())
            headers.setRawHeaders(b'user-agent', [self._user_agent])
            kwargs.setdefault('timeout', self.timeout)
            self._current_request = self._treq.request(method, url, *args,
                                                       **kwargs)
            return (DeferredContext(self._current_request).addCallback(
                cb_request_done).addCallback(
                    tap(lambda r: action.add_success_fields(
                        code=r.code,
                        content_type=r.headers.getRawHeaders(
                            b'content-type', [None])[0]))).addActionFinish())
예제 #4
0
파일: client.py 프로젝트: twisted/txacme
    def answer_challenge(self, challenge_body, response):
        """
        Respond to an authorization challenge.

        This send a POST with the empty object '{}' as the payload.

        :param ~acme.messages.ChallengeBody challenge_body: The challenge being
            responded to.
        :param ~acme.challenges.ChallengeResponse response: The response to the
            challenge.

        :return: The updated challenge resource.
        :rtype: Deferred[`~acme.messages.ChallengeResource`]
        """
        action = LOG_ACME_ANSWER_CHALLENGE(challenge_body=challenge_body,
                                           response=response)

        if challenge_body.status != STATUS_PENDING:
            # We already have an answer.
            return challenge_body

        with action.context():
            return (DeferredContext(
                self._client.post(
                    challenge_body.uri,
                    jose.JSONObjectWithFields())).addCallback(
                        self._parse_challenge).addCallback(
                            self._check_challenge, challenge_body).addCallback(
                                tap(lambda c: action.add_success_fields(
                                    challenge_resource=c))).addActionFinish())
예제 #5
0
파일: client.py 프로젝트: twisted/txacme
    def register(self, email=None):
        """
        Create a new registration with the ACME server or update
        an existing account.

        It should be called before doing any ACME requests.

        :param str: Comma separated contact emails used by the account.

        :return: The registration resource.
        :rtype: Deferred[`~acme.messages.RegistrationResource`]
        """
        uri = self.directory.newAccount
        new_reg = messages.Registration.from_data(
            email=email,
            terms_of_service_agreed=True,
        )
        action = LOG_ACME_REGISTER(registration=new_reg)
        with action.context():
            return (DeferredContext(
                self._client.post(uri, new_reg)).addCallback(
                    self._cb_check_existing_account, new_reg).addCallback(
                        self._cb_check_registration).addCallback(
                            tap(lambda r: action.add_success_fields(
                                registration=r))).addActionFinish())
예제 #6
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)))
         )
예제 #7
0
파일: client.py 프로젝트: habnabit/txacme
 def poll(self, authzr):
     """
     Update an authorization from the server (usually to check its status).
     """
     action = LOG_ACME_POLL_AUTHORIZATION(authorization=authzr)
     with action.context():
         return (
             DeferredContext(self._client.get(authzr.uri))
             # Spec says we should get 202 while pending, Boulder actually
             # sends us 200 always, so just don't check.
             # .addCallback(self._expect_response, http.ACCEPTED)
             .addCallback(
                 lambda res:
                 self._parse_authorization(res, uri=authzr.uri)
                 .addCallback(
                     self._check_authorization, authzr.body.identifier)
                 .addCallback(
                     lambda authzr:
                     (authzr,
                      self.retry_after(res, _now=self._clock.seconds)))
             )
             .addCallback(tap(
                 lambda a_r: action.add_success_fields(
                     authorization=a_r[0], retry_after=a_r[1])))
             .addActionFinish())
예제 #8
0
    def from_url(cls, reactor, url, key, alg=jose.RS256, jws_client=None):
        """
        Construct a client from an ACME directory at a given URL.

        :param url: The ``twisted.python.url.URL`` to fetch the directory from.
            See `txacme.urls` for constants for various well-known public
            directories.
        :param reactor: The Twisted reactor to use.
        :param ~acme.jose.jwk.JWK key: The client key to use.
        :param alg: The signing algorithm to use.  Needs to be compatible with
            the type of key used.
        :param JWSClient jws_client: The underlying client to use, or ``None``
            to construct one.

        :return: The constructed client.
        :rtype: Deferred[`Client`]
        """
        action = LOG_ACME_CONSUME_DIRECTORY(
            url=url, key_type=key.typ, alg=alg.name)
        with action.context():
            check_directory_url_type(url)
            jws_client = _default_client(jws_client, reactor, key, alg)
            return (
                DeferredContext(jws_client.get(url.asText()))
                .addCallback(json_content)
                .addCallback(messages.Directory.from_json)
                .addCallback(
                    tap(lambda d: action.add_success_fields(directory=d)))
                .addCallback(cls, reactor, key, jws_client)
                .addActionFinish())
예제 #9
0
    def update_registration(self, regr, uri=None):
        """
        Submit a registration to the server to update it.

        :param ~acme.messages.RegistrationResource regr: The registration to
            update.  Can be a :class:`~acme.messages.NewRegistration` instead,
            in order to create a new registration.
        :param str uri: The url to submit to.  Must be
            specified if a :class:`~acme.messages.NewRegistration` is provided.

        :return: The updated registration resource.
        :rtype: Deferred[`~acme.messages.RegistrationResource`]
        """
        if uri is None:
            uri = regr.uri
        if isinstance(regr, messages.RegistrationResource):
            message = messages.UpdateRegistration(**dict(regr.body))
        else:
            message = regr
        action = LOG_ACME_UPDATE_REGISTRATION(uri=uri, registration=message)
        with action.context():
            return (
                DeferredContext(self._client.post(uri, message))
                .addCallback(self._parse_regr_response, uri=uri)
                .addCallback(self._check_regr, regr)
                .addCallback(
                    tap(lambda r: action.add_success_fields(registration=r)))
                .addActionFinish())
예제 #10
0
파일: client.py 프로젝트: habnabit/txacme
    def update_registration(self, regr, uri=None):
        """
        Submit a registration to the server to update it.

        :param ~acme.messages.RegistrationResource regr: The registration to
            update.  Can be a :class:`~acme.messages.NewRegistration` instead,
            in order to create a new registration.
        :param str uri: The url to submit to.  Must be
            specified if a :class:`~acme.messages.NewRegistration` is provided.

        :return: The updated registration resource.
        :rtype: Deferred[`~acme.messages.RegistrationResource`]
        """
        if uri is None:
            uri = regr.uri
        if isinstance(regr, messages.RegistrationResource):
            message = messages.UpdateRegistration(**dict(regr.body))
        else:
            message = regr
        action = LOG_ACME_UPDATE_REGISTRATION(uri=uri, registration=message)
        with action.context():
            return (
                DeferredContext(self._client.post(uri, message))
                .addCallback(self._parse_regr_response, uri=uri)
                .addCallback(self._check_regr, regr)
                .addCallback(
                    tap(lambda r: action.add_success_fields(registration=r)))
                .addActionFinish())
예제 #11
0
파일: client.py 프로젝트: habnabit/txacme
    def from_url(cls, reactor, url, key, alg=jose.RS256, jws_client=None):
        """
        Construct a client from an ACME directory at a given URL.

        :param url: The ``twisted.python.url.URL`` to fetch the directory from.
        :param reactor: The Twisted reactor to use.
        :param ~acme.jose.jwk.JWK key: The client key to use.
        :param alg: The signing algorithm to use.  Needs to be compatible with
            the type of key used.
        :param JWSClient jws_client: The underlying client to use, or ``None``
            to construct one.

        :return: The constructed client.
        :rtype: Deferred[`Client`]
        """
        action = LOG_ACME_CONSUME_DIRECTORY(
            url=url, key_type=key.typ, alg=alg.name)
        with action.context():
            jws_client = _default_client(jws_client, reactor, key, alg)
            return (
                DeferredContext(jws_client.get(url.asText()))
                .addCallback(json_content)
                .addCallback(messages.Directory.from_json)
                .addCallback(
                    tap(lambda d: action.add_success_fields(directory=d)))
                .addCallback(cls, reactor, key, jws_client)
                .addActionFinish())
예제 #12
0
파일: service.py 프로젝트: twisted/txacme
    def stopService(self):
        Service.stopService(self)
        self.ready = False
        for d in list(self._waiting):
            d.cancel()
        self._waiting = []

        def stop_timer(ignored):
            if not self._timer_service:
                return
            return self._timer_service.stopService()

        def cleanup(ignored):
            self._timer_service = None

        return (self._client.stop().addBoth(tap(stop_timer)).addBoth(
            tap(cleanup)))
예제 #13
0
파일: service.py 프로젝트: habnabit/txacme
            def got_challenge(r):
                responder, response = r

                def stop_responding(result):
                    return responder.stop_responding(response)

                return (
                    poll_until_valid(authzr, self._clock, self._client)
                    .addBoth(tap(stop_responding)))
예제 #14
0
파일: client.py 프로젝트: twisted/txacme
 def _get_nonce(self, url):
     """
     Get a nonce to use in a request, removing it from the nonces on hand.
     """
     action = LOG_JWS_GET_NONCE()
     if len(self._nonces) > 0:
         with action:
             nonce = self._nonces.pop()
             action.add_success_fields(nonce=nonce)
             return defer.succeed(nonce)
     else:
         with action.context():
             return (DeferredContext(self.head(
                 self._new_nonce)).addCallback(self._add_nonce).addCallback(
                     lambda _: self._nonces.pop()).addCallback(
                         tap(lambda nonce: action.add_success_fields(
                             nonce=nonce))).addActionFinish())
예제 #15
0
파일: client.py 프로젝트: habnabit/txacme
 def _get_nonce(self, url):
     """
     Get a nonce to use in a request, removing it from the nonces on hand.
     """
     action = LOG_JWS_GET_NONCE()
     if len(self._nonces) > 0:
         with action:
             nonce = self._nonces.pop()
             action.add_success_fields(nonce=nonce)
             return succeed(nonce)
     else:
         with action.context():
             return (
                 DeferredContext(self.head(url))
                 .addCallback(self._add_nonce)
                 .addCallback(lambda _: self._nonces.pop())
                 .addCallback(tap(
                     lambda nonce: action.add_success_fields(nonce=nonce)))
                 .addActionFinish())
예제 #16
0
    def _send_request(self, method, url, *args, **kwargs):
        """
        Send HTTP request.

        :param str method: The HTTP method to use.
        :param str url: The URL to make the request to.

        :return: Deferred firing with the HTTP response.
        """
        action = LOG_JWS_REQUEST(url=url)
        with action.context():
            headers = kwargs.setdefault('headers', Headers())
            headers.setRawHeaders(b'user-agent', [self._user_agent])
            kwargs.setdefault('timeout', self.timeout)
            return (DeferredContext(
                self._treq.request(method, url, *args, **kwargs)).addCallback(
                    tap(lambda r: action.add_success_fields(
                        code=r.code,
                        content_type=r.headers.getRawHeaders(
                            b'content-type', [None])[0]))).addActionFinish())
예제 #17
0
    def register(self, new_reg=None):
        """
        Create a new registration with the ACME server.

        :param ~acme.messages.NewRegistration new_reg: The registration message
            to use, or ``None`` to construct one.

        :return: The registration resource.
        :rtype: Deferred[`~acme.messages.RegistrationResource`]
        """
        if new_reg is None:
            new_reg = messages.NewRegistration()
        action = LOG_ACME_REGISTER(registration=new_reg)
        with action.context():
            return (DeferredContext(
                self.update_registration(
                    new_reg, uri=self.directory[new_reg])).addErrback(
                        self._maybe_registered, new_reg).addCallback(
                            tap(lambda r: action.add_success_fields(
                                registration=r))).addActionFinish())
예제 #18
0
파일: client.py 프로젝트: twisted/txacme
    def from_url(
        cls,
        reactor,
        url,
        key,
        alg=RS256,
        jws_client=None,
        timeout=_DEFAULT_TIMEOUT,
    ):
        """
        Construct a client from an ACME directory at a given URL.

        At construct time, it validates the ACME directory.

        :param url: The ``twisted.python.url.URL`` to fetch the directory from.
            See `txacme.urls` for constants for various well-known public
            directories.
        :param reactor: The Twisted reactor to use.
        :param ~josepy.jwk.JWK key: The client key to use.
        :param alg: The signing algorithm to use.  Needs to be compatible with
            the type of key used.
        :param JWSClient jws_client: The underlying client to use, or ``None``
            to construct one.
        :param int timeout: Number of seconds to wait for an HTTP response
            during ACME server interaction.

        :return: The constructed client.
        :rtype: Deferred[`Client`]
        """
        action = LOG_ACME_CONSUME_DIRECTORY(url=url,
                                            key_type=key.typ,
                                            alg=alg.name)
        with action.context():
            check_directory_url_type(url)
            directory = url.asText()
            return (DeferredContext(jws_client=_default_client(
                jws_client, reactor, key, alg, directory, timeout
            )).addCallback(
                tap(lambda jws_client: action.add_success_fields(
                    directory=directory))).addCallback(lambda jws_client: cls(
                        reactor, key, jws_client)).addActionFinish())
예제 #19
0
    def answer_challenge(self, challenge_body, response):
        """
        Respond to an authorization challenge.

        :param ~acme.messages.ChallengeBody challenge_body: The challenge being
            responded to.
        :param ~acme.challenges.ChallengeResponse response: The response to the
            challenge.

        :return: The updated challenge resource.
        :rtype: Deferred[`~acme.messages.ChallengeResource`]
        """
        action = LOG_ACME_ANSWER_CHALLENGE(challenge_body=challenge_body,
                                           response=response)
        with action.context():
            return (DeferredContext(
                self._client.post(challenge_body.uri, response)).addCallback(
                    self._parse_challenge).addCallback(
                        self._check_challenge, challenge_body).addCallback(
                            tap(lambda c: action.add_success_fields(
                                challenge_resource=c))).addActionFinish())
예제 #20
0
    def request_challenges(self, identifier):
        """
        Create a new authorization.

        :param ~acme.messages.Identifier identifier: The identifier to
            authorize.

        :return: The new authorization resource.
        :rtype: Deferred[`~acme.messages.AuthorizationResource`]
        """
        action = LOG_ACME_CREATE_AUTHORIZATION(identifier=identifier)
        with action.context():
            message = messages.NewAuthorization(identifier=identifier)
            return (
                DeferredContext(
                    self._client.post(self.directory[message], message))
                .addCallback(self._expect_response, http.CREATED)
                .addCallback(self._parse_authorization)
                .addCallback(self._check_authorization, identifier)
                .addCallback(
                    tap(lambda a: action.add_success_fields(authorization=a)))
                .addActionFinish())
예제 #21
0
파일: client.py 프로젝트: habnabit/txacme
    def register(self, new_reg=None):
        """
        Create a new registration with the ACME server.

        :param ~acme.messages.NewRegistration new_reg: The registration message
            to use, or ``None`` to construct one.

        :return: The registration resource.
        :rtype: Deferred[`~acme.messages.RegistrationResource`]
        """
        if new_reg is None:
            new_reg = messages.NewRegistration()
        action = LOG_ACME_REGISTER(registration=new_reg)
        with action.context():
            return (
                DeferredContext(
                    self.update_registration(
                        new_reg, uri=self.directory[new_reg]))
                .addErrback(self._maybe_registered)
                .addCallback(
                    tap(lambda r: action.add_success_fields(registration=r)))
                .addActionFinish())
예제 #22
0
파일: client.py 프로젝트: habnabit/txacme
    def request_challenges(self, identifier):
        """
        Create a new authorization.

        :param ~acme.messages.Identifier identifier: The identifier to
            authorize.

        :return: The new authorization resource.
        :rtype: Deferred[`~acme.messages.AuthorizationResource`]
        """
        action = LOG_ACME_CREATE_AUTHORIZATION(identifier=identifier)
        with action.context():
            message = messages.NewAuthorization(identifier=identifier)
            return (
                DeferredContext(
                    self._client.post(self.directory[message], message))
                .addCallback(self._expect_response, http.CREATED)
                .addCallback(self._parse_authorization)
                .addCallback(self._check_authorization, identifier)
                .addCallback(
                    tap(lambda a: action.add_success_fields(authorization=a)))
                .addActionFinish())
예제 #23
0
파일: client.py 프로젝트: habnabit/txacme
    def _send_request(self, method, url, *args, **kwargs):
        """
        Send HTTP request.

        :param str method: The HTTP method to use.
        :param str url: The URL to make the request to.

        :return: Deferred firing with the HTTP response.
        """
        action = LOG_JWS_REQUEST(url=url)
        with action.context():
            headers = kwargs.setdefault('headers', Headers())
            headers.setRawHeaders(b'user-agent', [self._user_agent])
            kwargs.setdefault('timeout', self.timeout)
            return (
                DeferredContext(
                    self._treq.request(method, url, *args, **kwargs))
                .addCallback(
                    tap(lambda r: action.add_success_fields(
                        code=r.code,
                        content_type=r.headers.getRawHeaders(
                            b'content-type', [None])[0])))
                .addActionFinish())
예제 #24
0
파일: client.py 프로젝트: habnabit/txacme
    def answer_challenge(self, challenge_body, response):
        """
        Respond to an authorization challenge.

        :param ~acme.messages.ChallengeBody challenge_body: The challenge being
            responded to.
        :param ~acme.challenges.ChallengeResponse response: The response to the
            challenge.

        :return: The updated challenge resource.
        :rtype: Deferred[`~acme.messages.ChallengeResource`]
        """
        action = LOG_ACME_ANSWER_CHALLENGE(
            challenge_body=challenge_body, response=response)
        with action.context():
            return (
                DeferredContext(
                    self._client.post(challenge_body.uri, response))
                .addCallback(self._parse_challenge)
                .addCallback(self._check_challenge, challenge_body)
                .addCallback(
                    tap(lambda c:
                        action.add_success_fields(challenge_resource=c)))
                .addActionFinish())
예제 #25
0
파일: service.py 프로젝트: tomprince/txacme
 def got_challenge(stop_responding):
     return (
         poll_until_valid(authzr, self._clock, client)
         .addBoth(tap(lambda _: stop_responding())))
예제 #26
0
파일: service.py 프로젝트: mithrandi/txacme
 def got_challenge(stop_responding):
     return (
         poll_until_valid(authzr, self._clock, client)
         .addBoth(tap(lambda _: stop_responding())))