Setuptools entry_points plugins

This commit is contained in:
Jakub Warmuz
2015-03-26 13:55:23 +00:00
parent 197125bdda
commit ff532469a5
9 changed files with 87 additions and 18 deletions
+1
View File
@@ -7,6 +7,7 @@ Welcome to the Let's Encrypt client documentation!
intro intro
using using
contributing contributing
plugins
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
+5
View File
@@ -0,0 +1,5 @@
=======
Plugins
=======
You can find an example in ``examples/plugins/`` directory.
@@ -0,0 +1,16 @@
"""Example Let's Encrypt plugins."""
import zope.interface
from letsencrypt.client import interfaces
class Authenticator(object):
zope.interface.implements(interfaces.IAuthenticator)
description = 'Example Authenticator plugin'
def __init__(self, config):
self.config = config
# Implement all methods from IAuthenticator, remembering to add
# "self" as first argument, e.g. def prepare(self)...
+16
View File
@@ -0,0 +1,16 @@
from setuptools import setup
setup(
name='letsencrypt-example-plugins',
package='letsencrypt_example_plugins.py',
install_requires=[
'letsencrypt',
'zope.interface',
],
entry_points={
'letsencrypt.authenticators': [
'example = letsencrypt_example_plugins:Authenticator',
],
},
)
+27
View File
@@ -1,11 +1,15 @@
"""ACME protocol client class and helper functions.""" """ACME protocol client class and helper functions."""
import logging import logging
import os import os
import pkg_resources
import sys import sys
import Crypto.PublicKey.RSA import Crypto.PublicKey.RSA
import M2Crypto import M2Crypto
import zope.interface.exceptions
import zope.interface.verify
from letsencrypt.acme import messages from letsencrypt.acme import messages
from letsencrypt.acme.jose import util as jose_util from letsencrypt.acme.jose import util as jose_util
@@ -13,6 +17,7 @@ from letsencrypt.client import auth_handler
from letsencrypt.client import client_authenticator from letsencrypt.client import client_authenticator
from letsencrypt.client import crypto_util from letsencrypt.client import crypto_util
from letsencrypt.client import errors from letsencrypt.client import errors
from letsencrypt.client import interfaces
from letsencrypt.client import le_util from letsencrypt.client import le_util
from letsencrypt.client import network from letsencrypt.client import network
from letsencrypt.client import reverter from letsencrypt.client import reverter
@@ -23,6 +28,28 @@ from letsencrypt.client.display import ops as display_ops
from letsencrypt.client.display import enhancements from letsencrypt.client.display import enhancements
SETUPTOOLS_AUTHENTICATORS_ENTRY_POINT = 'letsencrypt.authenticators'
"""Setuptools entry point group name for Authenticator plugins."""
def init_auths(config):
"""Find (setuptools entry points) and initialize Authenticators."""
auths = {}
for entrypoint in pkg_resources.iter_entry_points(
SETUPTOOLS_AUTHENTICATORS_ENTRY_POINT):
auth_cls = entrypoint.load()
auth = auth_cls(config)
try:
zope.interface.verify.verifyObject(interfaces.IAuthenticator, auth)
except zope.interface.exceptions.BrokenImplementation:
logging.debug(
'"%s" object does not provide IAuthenticator, skipping',
entrypoint.name)
else:
auths[auth] = entrypoint.name
return auths
class Client(object): class Client(object):
"""ACME protocol client. """ACME protocol client.
@@ -33,7 +33,7 @@ class StandaloneAuthenticator(object):
description = "Standalone Authenticator" description = "Standalone Authenticator"
def __init__(self): def __init__(self, unused_config):
self.child_pid = None self.child_pid = None
self.parent_pid = os.getpid() self.parent_pid = os.getpid()
self.subproc_state = None self.subproc_state = None
@@ -51,7 +51,7 @@ class ChallPrefTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
def test_chall_pref(self): def test_chall_pref(self):
self.assertEqual(self.authenticator.get_chall_pref("example.com"), self.assertEqual(self.authenticator.get_chall_pref("example.com"),
@@ -63,7 +63,7 @@ class SNICallbackTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
test_key = pkg_resources.resource_string( test_key = pkg_resources.resource_string(
__name__, "testdata/rsa256_key.pem") __name__, "testdata/rsa256_key.pem")
key = le_util.Key("foo", test_key) key = le_util.Key("foo", test_key)
@@ -106,7 +106,7 @@ class ClientSignalHandlerTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
self.authenticator.tasks = {"foononce.acme.invalid": "stuff"} self.authenticator.tasks = {"foononce.acme.invalid": "stuff"}
self.authenticator.child_pid = 12345 self.authenticator.child_pid = 12345
@@ -135,7 +135,7 @@ class SubprocSignalHandlerTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
self.authenticator.tasks = {"foononce.acme.invalid": "stuff"} self.authenticator.tasks = {"foononce.acme.invalid": "stuff"}
self.authenticator.child_pid = 12345 self.authenticator.child_pid = 12345
self.authenticator.parent_pid = 23456 self.authenticator.parent_pid = 23456
@@ -187,7 +187,7 @@ class AlreadyListeningTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
@mock.patch("letsencrypt.client.standalone_authenticator.psutil." @mock.patch("letsencrypt.client.standalone_authenticator.psutil."
"net_connections") "net_connections")
@@ -290,7 +290,7 @@ class PerformTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
test_key = pkg_resources.resource_string( test_key = pkg_resources.resource_string(
__name__, "testdata/rsa256_key.pem") __name__, "testdata/rsa256_key.pem")
@@ -367,7 +367,7 @@ class StartListenerTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
@mock.patch("letsencrypt.client.standalone_authenticator." @mock.patch("letsencrypt.client.standalone_authenticator."
"Crypto.Random.atfork") "Crypto.Random.atfork")
@@ -402,7 +402,7 @@ class DoParentProcessTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
@mock.patch("letsencrypt.client.standalone_authenticator.signal.signal") @mock.patch("letsencrypt.client.standalone_authenticator.signal.signal")
@mock.patch("letsencrypt.client.standalone_authenticator." @mock.patch("letsencrypt.client.standalone_authenticator."
@@ -452,7 +452,7 @@ class DoChildProcessTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
test_key = pkg_resources.resource_string( test_key = pkg_resources.resource_string(
__name__, "testdata/rsa256_key.pem") __name__, "testdata/rsa256_key.pem")
key = le_util.Key("foo", test_key) key = le_util.Key("foo", test_key)
@@ -545,7 +545,7 @@ class CleanupTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import \ from letsencrypt.client.standalone_authenticator import \
StandaloneAuthenticator StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
self.achall = achallenges.DVSNI( self.achall = achallenges.DVSNI(
chall=challenges.DVSNI(r="whee", nonce="foononce"), chall=challenges.DVSNI(r="whee", nonce="foononce"),
domain="foo.example.com", key="key") domain="foo.example.com", key="key")
@@ -575,7 +575,7 @@ class MoreInfoTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import ( from letsencrypt.client.standalone_authenticator import (
StandaloneAuthenticator) StandaloneAuthenticator)
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
def test_more_info(self): def test_more_info(self):
"""Make sure exceptions aren't raised.""" """Make sure exceptions aren't raised."""
@@ -587,7 +587,7 @@ class InitTest(unittest.TestCase):
def setUp(self): def setUp(self):
from letsencrypt.client.standalone_authenticator import ( from letsencrypt.client.standalone_authenticator import (
StandaloneAuthenticator) StandaloneAuthenticator)
self.authenticator = StandaloneAuthenticator() self.authenticator = StandaloneAuthenticator(None)
def test_prepare(self): def test_prepare(self):
"""Make sure exceptions aren't raised. """Make sure exceptions aren't raised.
+3 -5
View File
@@ -136,12 +136,10 @@ def main(): # pylint: disable=too-many-branches, too-many-statements
if not args.eula: if not args.eula:
display_eula() display_eula()
all_auths = [ all_auths = client.init_auths(config)
configurator.ApacheConfigurator(config), logging.debug('Initialized authenticators: %s', all_auths)
standalone.StandaloneAuthenticator(),
]
try: try:
auth = client.determine_authenticator(all_auths) auth = client.determine_authenticator(all_auths.keys())
except errors.LetsEncryptClientError: except errors.LetsEncryptClientError:
logging.critical("No authentication mechanisms were found on your " logging.critical("No authentication mechanisms were found on your "
"system.") "system.")
+6
View File
@@ -119,6 +119,12 @@ setup(
'letsencrypt = letsencrypt.scripts.main:main', 'letsencrypt = letsencrypt.scripts.main:main',
'jws = letsencrypt.acme.jose.jws:CLI.run', 'jws = letsencrypt.acme.jose.jws:CLI.run',
], ],
'letsencrypt.authenticators': [
'apache = letsencrypt.client.apache.configurator'
':ApacheConfigurator',
'standalone = letsencrypt.client.standalone_authenticator'
':StandaloneAuthenticator',
],
}, },
zip_safe=False, zip_safe=False,