Example #1
0
    def update_registration(self, regr):
        """Update registration.

        :pram regr: Registration Resource.
        :type regr: `.RegistrationResource`

        :returns: Updated Registration Resource.
        :rtype: `.RegistrationResource`

        """
        response = self.net.post(
            regr.uri, messages.UpdateRegistration(**dict(regr.body)))

        # TODO: Boulder returns httplib.ACCEPTED
        #assert response.status_code == httplib.OK

        # TODO: Boulder does not set Location or Link on update
        # (c.f. acme-spec #94)

        updated_regr = self._regr_from_response(
            response, uri=regr.uri, new_authzr_uri=regr.new_authzr_uri,
            terms_of_service=regr.terms_of_service)
        if updated_regr != regr:
            raise errors.UnexpectedUpdate(regr)
        return updated_regr
Example #2
0
def register(ctx, email, phone, auto_accept_tos, quiet=False):
    regr = ctx.obj['acme'].register(
        messages.NewRegistration.from_data(email=email, phone=phone))
    if regr.body.agreement != regr.terms_of_service:
        if not auto_accept_tos and not click.confirm(
                'Accept Terms of Service? (%s)' % regr.terms_of_service,
                default=None):
            ctx.fail('Must accept ToS to continue')
        elif auto_accept_tos:
            logger.info('automatically accepting ToS')
        ctx.obj['acme'].agree_to_tos(regr)

    if (email and
        (email, ) != regr.body.emails) or (phone and
                                           (phone, ) != regr.body.phones):
        logger.info('updating contact information')
        upd_reg = messages.UpdateRegistration().from_data(email=email,
                                                          phone=phone)
        try:
            regr = ctx.obj['acme'].update_registration(regr, upd_reg)
        except errors.UnexpectedUpdate:
            pass  # no idea why it complains, but updates anyway
        regr = ctx.obj['acme'].query_registration(regr)

    if not quiet:
        click.echo('Registration:')
        click.echo('Email: %s' % (regr.body.emails, ))
        click.echo('Phone: %s' % (regr.body.phones, ))
    else:
        return regr
Example #3
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())
Example #4
0
    def query_registration(self, regr):
        """Query server about registration.

        :param messages.RegistrationResource: Existing Registration
            Resource.

        """
        return self._send_recv_regr(regr, messages.UpdateRegistration())
Example #5
0
File: reg.py Project: ponchov/wile
def register(ctx, email, phone, auto_accept_tos, quiet=False):
    '''
    Register a new account key or update an existing registration.
    '''

    logger.info('starting registration for email:"%s", phone:"%s"', email,
                phone)
    try:
        regr = ctx.obj.acme.register(
            messages.NewRegistration.from_data(email=email, phone=phone))
    except errors.ConflictError as e:
        logger.info('found existing registration for key; fetching')
        response = ctx.obj.acme.net.post(e.location,
                                         messages.UpdateRegistration())
        regr = client.Client._regr_from_response(response, uri=e.location)

    if regr.body.agreement != regr.terms_of_service:
        if not auto_accept_tos and not click.confirm(
                'Accept Terms of Service? (%s)' % regr.terms_of_service,
                default=None):
            ctx.fail('Must accept ToS to continue')
        elif auto_accept_tos:
            logger.info('automatically accepting ToS')
        ctx.obj.acme.agree_to_tos(regr)

    if (email and
        (email, ) != regr.body.emails) or (phone and
                                           (phone, ) != regr.body.phones):
        logger.info('updating contact information')
        upd_reg = messages.UpdateRegistration().from_data(email=email,
                                                          phone=phone)
        try:
            regr = ctx.obj.acme.update_registration(regr, upd_reg)
        except errors.UnexpectedUpdate:
            pass  # no idea why it complains, but updates anyway
        regr = ctx.obj.acme.query_registration(regr)

    if not quiet:
        click.echo('Registration:')
        click.echo('Email: %s' % (regr.body.emails or ''))
        click.echo('Phone: %s' % (regr.body.phones or ''))
    else:
        return regr
Example #6
0
 def _maybe_registered(self, failure):
     """
     If the registration already exists, we should just load it.
     """
     failure.trap(ServerError)
     response = failure.value.response
     if response.code == http.CONFLICT:
         uri = self._maybe_location(response)
         return self.update_registration(
             messages.UpdateRegistration(), uri=uri)
     return failure
Example #7
0
def _monkeypatch_register(self, new_reg=None):
    new_reg = new_reg or messages.NewRegistration()
    response = self.net.post(self.directory[new_reg],
                             new_reg,
                             check_response=False)
    loc = None
    if response.status_code == client.http_client.CONFLICT and response.headers.get(
            'Location'):
        reg = messages.UpdateRegistration()
        loc = response.headers.get('Location')
        response = self.net.post(loc, reg)
    return self._regr_from_response(response, uri=loc)
    def update_registration(self, regr, update=None):
        """Update registration.

        :param messages.RegistrationResource regr: Registration Resource.
        :param messages.Registration update: Updated body of the
            resource. If not provided, body will be taken from `regr`.

        :returns: Updated Registration Resource.
        :rtype: `.RegistrationResource`

        """
        update = regr.body if update is None else update
        body = messages.UpdateRegistration(**dict(update))
        updated_regr = self._send_recv_regr(regr, body=body)
        return updated_regr
Example #9
0
    async def connect(cls,
                      directory: str,
                      key: crypto.PrivateKey,
                      *,
                      loop: _T_AIO_LOOP = None) -> 'AsyncmeClient':
        """
        Connect to an ACME server.

        :param directory: The URI of the ACME server's directory.
        :param key: Private key used for interacting with the ACME server.
        :param loop: Event loop.

        :return: A new instance of ``AsyncmeClient`` which has been
         registered against the given ACME server, if the key has not already
         been registered.
        """

        # Determine the JWS 'alg' Type for the Given Key
        # RSA
        if key.algorithm is crypto.KeyAlgorithmType.RSA:
            if key.size / 8 == 256:
                alg = jose.jwa.RS256
            elif key.size / 8 == 384:
                alg = jose.jwa.RS384
            elif key.size / 8 == 512:
                alg = jose.jwa.RS512
            else:
                raise ValueError("RSA key size of {} "
                                 "is unsupported".format(key.size))

        # ECDSA
        elif key.algorithm is crypto.KeyAlgorithmType.ECDSA:
            if key.size == 256:
                alg = jose.jwa.ES256
            elif key.size == 384:
                alg = jose.jwa.ES384
            elif key.size == 521:
                alg = jose.jwa.ES512
            else:
                raise ValueError("ECDSA key size of {} "
                                 "is unsupported".format(key.size))

        # Other
        else:
            raise ValueError("Unsupported private key type, must "
                             "be RSA or ECDSA")

        # Convert Key
        password = os.urandom(255)
        acme_key = jose.JWKRSA(key=serialization.load_der_private_key(
            key.to_bytes(encoding=crypto.EncodingType.DER, password=password),
            password, default_backend()))

        # Get Async. Loop
        loop = loop or asyncio.get_event_loop()

        # Instantiate Underlying Client
        # (and make the initial connection to the ACME server)
        try:
            client = await ExecutorClient.connect(
                directory=directory,
                key=acme_key,
                alg=alg,
                net=ExtendedNetwork(
                    key=acme_key,
                    alg=alg,
                    user_agent='asyncme-python-{}'.format(ASYNCME_VERSION)),
                loop=loop)
        except TypeError:
            raise ValueError("Invalid ACME directory given")

        # Client Registration
        try:
            regr = await client.register()
        except errors.Error as e:

            # The upstream client currently has no way to "recover" a lost
            # registration resource, thus we must resort to the tactics below.

            if "key is already in use" in str(e):

                LOG.debug("Key already in use: attempting to recover "
                          "registration resource.")

                # (1) Send a Post in Attempt to Register the Client
                #     and Get a 409 Back in Response with Location
                #     Header set.

                post = functools.partial(client.net.post,
                                         client.directory['new-reg'],
                                         messages.NewRegistration(),
                                         checked=False)
                response = await loop.run_in_executor(None, post)
                assert response.status_code == 409

                # (2) Manually create a new Registration Resource and
                #     send an empty registration update.
                #     (per draft-ietf-acme-acme-03#section-6.2)

                regr = messages.RegistrationResource(
                    uri=response.headers.get("location"))

                # Empty Update
                regr = await client._send_recv_regr(
                    regr, body=messages.UpdateRegistration())

            else:
                raise RuntimeError(e)

        return cls(client, regr)