diff --git a/letsencrypt/account.py b/letsencrypt/account.py index 12389ebfd..b2b00a32e 100644 --- a/letsencrypt/account.py +++ b/letsencrypt/account.py @@ -1,9 +1,11 @@ """Creates ACME accounts for server.""" import datetime +import hashlib import logging import os import socket +from cryptography.hazmat.primitives import serialization import pyrfc3339 import pytz import zope.component @@ -20,15 +22,13 @@ from letsencrypt import le_util logger = logging.getLogger(__name__) -class Account(object): +class Account(object): # pylint: disable=too-few-public-methods """ACME protocol registration. :ivar .RegistrationResource regr: Registration Resource :ivar .JWK key: Authorized Account Key :ivar .Meta: Account metadata - - .. note:: ``creation_dt`` and ``creation_host`` are useful in - cross-machine migration scenarios. + :ivar str id: Globally unique account identifier. """ @@ -38,6 +38,9 @@ class Account(object): :ivar datetime.datetime creation_dt: Creation date and time (UTC). :ivar str creation_host: FQDN of host, where account has been created. + .. note:: ``creation_dt`` and ``creation_host`` are useful in + cross-machine migration scenarios. + """ creation_dt = acme_fields.RFC3339Field("creation_dt") creation_host = jose.Field("creation_host") @@ -51,18 +54,16 @@ class Account(object): tz=pytz.UTC).replace(microsecond=0), creation_host=socket.getfqdn()) if meta is None else meta - @property - def id(self): # pylint: disable=invalid-name - """Globally unique account identifier. - - Implementation note: Email? Multiple accounts can have the same - email address. Registration URI? Assigned by the server, not - guaranteed to be stable over time, nor cannonical URI can be - generated. One could use the account key (fingerprint), as ACME - protocol doesn't allow it to be updated... - - """ - return self.slug + self.id = hashlib.md5( # pylint: disable=invalid-name + self.key.key.public_key().public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo) + ).hexdigest() + # Implementation note: Email? Multiple accounts can have the + # same email address. Registration URI? Assigned by the + # server, not guaranteed to be stable over time, nor + # cannonical URI can be generated. ACME protocol doesn't allow + # account key (and thus its fingerprint) to be updated... @property def slug(self): diff --git a/letsencrypt/tests/account_test.py b/letsencrypt/tests/account_test.py index bd34edc56..c0a3f1848 100644 --- a/letsencrypt/tests/account_test.py +++ b/letsencrypt/tests/account_test.py @@ -45,7 +45,7 @@ class AccountTest(unittest.TestCase): def test_id(self): self.assertEqual( - self.acc.id, "test.letsencrypt.org@2015-07-04T14:04:10Z") + self.acc.id, "2ba35a3bdf380ed76a5ac9e740568395") def test_slug(self): self.assertEqual( @@ -54,7 +54,7 @@ class AccountTest(unittest.TestCase): def test_repr(self): self.assertEqual( repr(self.acc), - "") + "") class ReportNewAccountTest(unittest.TestCase): diff --git a/letsencrypt/tests/display/ops_test.py b/letsencrypt/tests/display/ops_test.py index aba711150..6f4b2f317 100644 --- a/letsencrypt/tests/display/ops_test.py +++ b/letsencrypt/tests/display/ops_test.py @@ -1,5 +1,6 @@ """Test letsencrypt.display.ops.""" import os +import pkg_resources import sys import tempfile import unittest @@ -7,6 +8,7 @@ import unittest import mock import zope.component +from acme import jose from acme import messages from letsencrypt import account @@ -15,6 +17,10 @@ from letsencrypt import interfaces from letsencrypt.display import util as display_util +KEY = jose.JWKRSA.load(pkg_resources.resource_string( + "letsencrypt.tests", os.path.join("testdata", "rsa512_key.pem"))) + + class ChoosePluginTest(unittest.TestCase): """Tests for letsencrypt.display.ops.choose_plugin.""" @@ -186,7 +192,7 @@ class ChooseAccountTest(unittest.TestCase): accounts_dir=self.accounts_dir, account_keys_dir=self.account_keys_dir, server="letsencrypt-demo.org") - self.key = mock.MagicMock() + self.key = KEY self.acc1 = account.Account(messages.RegistrationResource( uri=None, new_authzr_uri=None, body=messages.Registration.from_data(