Skip to content

Commit

Permalink
start working on complete documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mswart committed Dec 17, 2015
1 parent 22ff3a3 commit 07cef8b
Show file tree
Hide file tree
Showing 14 changed files with 410 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ __pycache__
/.cache
/.coverage
/htmlcov
/docbuild
23 changes: 23 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
ChangeLog
=========

This page lists all versions with its changes. ACMEMS follows Semantic Versioning.


Version 0
-------------------------

v0.1.1
^^^^^^

* Fix syntax error in setup.py, preventing to upload to PyPI

v0.1.0
^^^^^^

Implement basic feature set:

* submit CSR
* validate domain via HTTP
* sign certificate
* authenticate clients based on IP and HMAC
9 changes: 9 additions & 0 deletions acmems/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def process(self, client_address, headers, rfile):


class IPAuthMethod():
''' Autentication by source IP'''
option_names = ['ip']

def __init__(self, ips=None):
Expand All @@ -57,6 +58,7 @@ def check(self, processor):


class HmacAuthMethod():
''' Authentication by HMAC / secret key '''
option_names = ['hmac_type', 'hmac_key']

def parse(self, option, value):
Expand Down Expand Up @@ -94,6 +96,7 @@ def check(self, processor):


class AllAuthMethod():
''' Allow all authentication'''
option_names = ['all']

def parse(self, option, value):
Expand All @@ -108,6 +111,9 @@ def check(self, processor):


class Block():
''' One authentication block - combination of authentications
and list of allowed domains
'''
def __init__(self, name, options):
self.name = name
self.methods = []
Expand Down Expand Up @@ -161,6 +167,9 @@ def parse(self, options):


class Processor():
''' Helper object to process a request, check authentication,
reads and parse CSR
'''
def __init__(self, auth, client_address, headers, rfile):
self.auth = auth
self.client_address = client_address
Expand Down
53 changes: 48 additions & 5 deletions acmems/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
class AcmeException(Exception):
''' Base exception call to be able to catch all ACMEMS specific
errors
'''
pass


class NeedToAgreeToTOS(AcmeException):
def __init__(self, url):
self.url = url


class NoChallengeMethodsSupported(AcmeException):
''' The domain can not be validated HTTP01
'''
pass


class ChallengeFailed(AcmeException):
''' The challenge to validate the requested domain failed.
:ivar str domain: the domain which the challenge should validate
:ivar str message: message description from ACME server
:ivar str challenge_uri: the URI of the failed challenge
'''
def __init__(self, domain, message, challenge_uri):
self.domain = domain
self.message = message
Expand All @@ -22,28 +28,59 @@ def __str__(self):


class ChallengesUnknownStatus(AcmeException):
''' We do not known the status of the challenge. No clue what to do '''
pass


class AuthorizationNotYetProcessed(AcmeException):
''' The authorization is be processed; until the next refresh it should
at least be wait until `~wait_until`
:ivar datetime.datetime wait_until: first allowed retry time
'''
def __init__(self, wait_until):
self.wait_until = wait_until


class AuthorizationNotYetRequested(AcmeException):
''' The newly created authorization challenge, was installed, but has not
yet been requested by any client and is therefore currently pending
or invalid.
:ivar threading.Event event: event that will be signaled if someone
requests the challenge.
'''
def __init__(self, event):
self.event = event


class RateLimited(AcmeException):
''' To many requests '''
pass


class AccountError(AcmeException):
''' Generic account error - e.g.
- could not read private key
- could not refresh the registration
'''
pass


class NeedToAgreeToTOS(AccountError):
''' We are registered at the ACME server. But to use it,
we need to accept the "Terms of Service"
'''
def __init__(self, url):
self.url = url


class InvalidDomainName(AcmeException):
''' The domain name is not excepted by the ACME server.
:ivar str domain: the domain that was rejected
:ivar str detail: the reject reason as string
'''
def __init__(self, domain, detail):
self.domain = domain
self.detail = detail
Expand All @@ -54,10 +91,16 @@ def __str__(self):


class PayloadToLarge(AcmeException):
''' The payload (CSR) it to large
:ivar int size: the request size to upload (in bytes)
:ivar int allowed: the maximal size in bytes
'''
def __init__(self, size, allowed):
self.size = size
self.allowed = allowed


class PayloadInvalid(AcmeException):
''' The payload is not a valid CSR '''
pass
27 changes: 16 additions & 11 deletions acmems/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ACMEManager():
:ivar dict responses: Responses to deliver; designed as answers for
authorization challenges. dict[host][path] = value
:ivar dict authzrs: List of current active `acme.message.AuthorizationResource`
:ivar dict authzrs: List of current active `acme.messages.AuthorizationResource`
:ivar acmems.config.Configuration config: Active configuration
'''
Expand Down Expand Up @@ -174,9 +174,10 @@ def acquire_domain_validations(self, domains):
Expired challenges will clear automatically; invalided challenges
will not.
:param list[str] domains: List of domains to validate
:return list[acme.message.Challenge]: Challenges for the requested
domains
:param domains: List of domains to validate
:type domains: list of `str`
:returns: Challenges for the requested domains
:rtype: acme.messages.ChallengeBody
'''
while True:
authzrs = []
Expand Down Expand Up @@ -218,16 +219,18 @@ def evaluate_domain_authorization(self, authzr, refresh_timer=None):
Renew revoked or expired ones.
Refresh pending/processing authorizations
:param acme.message.AuthorizationResource authzr: the authzr in
:param acme.messages.AuthorizationResource authzr: the authzr in
question
:return acme.message.AuthorizationResource: a valid authzr
:return: a valid authzr
:rtype: acme.messages.AuthorizationResource
:raises acmems.exceptions.AuthorizationNotYetProcessed: We have to
wait while the ACME server processes the autzr
:raises acmems.exceptions.AuthorizationNotYetRequested: new authzr
created; have to wait until someone requests it
:raises acmems.exceptions.ChallengesUnknownStatus: unknown status
:raises acmems.excpetions.NoChallengeMethodsSupported: HTTP01 is
:raises acmems.exceptions.NoChallengeMethodsSupported: HTTP01 is
not supported
:raises acmems.exceptions.ChallengeFailed: challenge failed
'''
authz = authzr.body
domain = authz.identifier.value
Expand Down Expand Up @@ -262,13 +265,14 @@ def refresh_domain_authorization(self, domain):
''' Refreshes a authorization for status changes
:param str domain: domain name for the authorization
:return acme.message.AuthorizationResource: a valid authzr
:return: a valid authzr
:rtype: acme.messages.AuthorizationResource
:raises acmems.exceptions.AuthorizationNotYetProcessed: We have to
wait while the ACME server processes the autzr
:raises acmems.exceptions.AuthorizationNotYetRequested: new authzr
created; have to wait until someone requests it
:raises acmems.exceptions.ChallengesUnknownStatus: unknown status
:raises acmems.excpetions.NoChallengeMethodsSupported: HTTP01 is
:raises acmems.exceptions.NoChallengeMethodsSupported: HTTP01 is
not supported
'''
self.log('Refresh authorization for {}'.format(domain))
Expand All @@ -281,13 +285,14 @@ def new_domain_authorization(self, domain):
''' Requests a complete new authorization for the given domain
:param str domain: domain name for the authorization
:return acme.message.AuthorizationResource: a valid authzr
:return: a valid authzr
:rtype: acme.messages.AuthorizationResource
:raises acmems.exceptions.AuthorizationNotYetProcessed: We have to
wait while the ACME server processes the autzr
:raises acmems.exceptions.AuthorizationNotYetRequested: new authzr
created; have to wait until someone requests it
:raises acmems.exceptions.ChallengesUnknownStatus: unknown status
:raises acmems.excpetions.NoChallengeMethodsSupported: HTTP01 is
:raises acmems.exceptions.NoChallengeMethodsSupported: HTTP01 is
not supported
'''
self.log('Requesting new authorization for {}'.format(domain))
Expand Down
1 change: 1 addition & 0 deletions doc/changelog.rst

0 comments on commit 07cef8b

Please sign in to comment.