diff --git a/AUTHORS.md b/AUTHORS.md index 340a0a94b..45d00eda7 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -15,6 +15,7 @@ Authors * [Alex Gaynor](https://github.com/alex) * [Alex Halderman](https://github.com/jhalderm) * [Alex Jordan](https://github.com/strugee) +* [Alex Zorin](https://github.com/alexzorin) * [Amjad Mashaal](https://github.com/TheNavigat) * [Andrew Murray](https://github.com/radarhere) * [Anselm Levskaya](https://github.com/levskaya) diff --git a/CHANGELOG.md b/CHANGELOG.md index 091ec0493..6f0da8ce1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Added -* +* acme: Authz deactivation added to `acme` module. ### Changed diff --git a/acme/acme/client.py b/acme/acme/client.py index 5a8fd88ae..9698c7609 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -123,6 +123,21 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes """ return self.update_registration(regr, update={'status': 'deactivated'}) + def deactivate_authorization(self, authzr): + # type: (messages.AuthorizationResource) -> messages.AuthorizationResource + """Deactivate authorization. + + :param messages.AuthorizationResource authzr: The Authorization resource + to be deactivated. + + :returns: The Authorization resource that was deactivated. + :rtype: `.AuthorizationResource` + + """ + body = messages.UpdateAuthorization(status='deactivated') + response = self._post(authzr.uri, body) + return self._authzr_from_response(response) + def _authzr_from_response(self, response, identifier=None, uri=None): authzr = messages.AuthorizationResource( body=messages.Authorization.from_json(response.json()), diff --git a/acme/acme/client_test.py b/acme/acme/client_test.py index 406201751..4c762031b 100644 --- a/acme/acme/client_test.py +++ b/acme/acme/client_test.py @@ -637,6 +637,14 @@ class ClientTest(ClientTestBase): errors.PollError, self.client.poll_and_request_issuance, csr, authzrs, mintime=mintime, max_attempts=2) + def test_deactivate_authorization(self): + authzb = self.authzr.body.update(status=messages.STATUS_DEACTIVATED) + self.response.json.return_value = authzb.to_json() + authzr = self.client.deactivate_authorization(self.authzr) + self.assertEqual(authzb, authzr.body) + self.assertEqual(self.client.net.post.call_count, 1) + self.assertTrue(self.authzr.uri in self.net.post.call_args_list[0][0]) + def test_check_cert(self): self.response.headers['Location'] = self.certr.uri self.response.content = CERT_DER diff --git a/acme/acme/messages.py b/acme/acme/messages.py index df96b5f2b..2bfe688d2 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -168,6 +168,7 @@ STATUS_VALID = Status('valid') STATUS_INVALID = Status('invalid') STATUS_REVOKED = Status('revoked') STATUS_READY = Status('ready') +STATUS_DEACTIVATED = Status('deactivated') class IdentifierType(_Constant): @@ -471,7 +472,7 @@ class Authorization(ResourceBody): :ivar datetime.datetime expires: """ - identifier = jose.Field('identifier', decoder=Identifier.from_json) + identifier = jose.Field('identifier', decoder=Identifier.from_json, omitempty=True) challenges = jose.Field('challenges', omitempty=True) combinations = jose.Field('combinations', omitempty=True) @@ -501,6 +502,12 @@ class NewAuthorization(Authorization): resource = fields.Resource(resource_type) +class UpdateAuthorization(Authorization): + """Update authorization.""" + resource_type = 'authz' + resource = fields.Resource(resource_type) + + class AuthorizationResource(ResourceWithURI): """Authorization Resource.