@ -437,7 +437,7 @@ class ACMEDirectory(object):
self . directory_root = module . params [ ' acme_directory ' ]
self . directory_root = module . params [ ' acme_directory ' ]
self . version = module . params [ ' acme_version ' ]
self . version = module . params [ ' acme_version ' ]
self . directory , dummy = account . get_request ( self . directory_root )
self . directory , dummy = account . get_request ( self . directory_root , get_only = True )
# Check whether self.version matches what we expect
# Check whether self.version matches what we expect
if self . version == 1 :
if self . version == 1 :
@ -520,7 +520,10 @@ class ACMEAccount(object):
def sign_request ( self , protected , payload , key_data ) :
def sign_request ( self , protected , payload , key_data ) :
try :
try :
payload64 = nopad_b64 ( self . module . jsonify ( payload ) . encode ( ' utf8 ' ) )
if payload is None :
payload64 = ' '
else :
payload64 = nopad_b64 ( self . module . jsonify ( payload ) . encode ( ' utf8 ' ) )
protected64 = nopad_b64 ( self . module . jsonify ( protected ) . encode ( ' utf8 ' ) )
protected64 = nopad_b64 ( self . module . jsonify ( protected ) . encode ( ' utf8 ' ) )
except Exception as e :
except Exception as e :
raise ModuleFailException ( " Failed to encode payload / headers as JSON: {0} " . format ( e ) )
raise ModuleFailException ( " Failed to encode payload / headers as JSON: {0} " . format ( e ) )
@ -535,6 +538,9 @@ class ACMEAccount(object):
Sends a JWS signed HTTP POST request to the ACME server and returns
Sends a JWS signed HTTP POST request to the ACME server and returns
the response as dictionary
the response as dictionary
https : / / tools . ietf . org / html / draft - ietf - acme - acme - 14 #section-6.2
https : / / tools . ietf . org / html / draft - ietf - acme - acme - 14 #section-6.2
If payload is None , a POST - as - GET is performed .
( https : / / tools . ietf . org / html / draft - ietf - acme - acme - 15 #section-6.3)
'''
'''
key_data = key_data or self . key_data
key_data = key_data or self . key_data
jws_header = jws_header or self . jws_header
jws_header = jws_header or self . jws_header
@ -580,14 +586,31 @@ class ACMEAccount(object):
return result , info
return result , info
def get_request ( self , uri , parse_json_result = True , headers = None ) :
def get_request ( self , uri , parse_json_result = True , headers = None , get_only = False ) :
resp , info = fetch_url ( self . module , uri , method = ' GET ' , headers = headers )
'''
Perform a GET - like request . Will try POST - as - GET for ACMEv2 , with fallback
to GET if server replies with a status code of 405.
'''
if not get_only and self . version != 1 :
# Try POST-as-GET
content , info = self . send_signed_request ( uri , None , parse_json_result = False )
if info [ ' status ' ] == 405 :
# Instead, do unauthenticated GET
get_only = True
else :
# Do unauthenticated GET
get_only = True
try :
if get_only :
content = resp . read ( )
# Perform unauthenticated GET
except AttributeError :
resp , info = fetch_url ( self . module , uri , method = ' GET ' , headers = headers )
content = info . get ( ' body ' )
try :
content = resp . read ( )
except AttributeError :
content = info . get ( ' body ' )
# Process result
if parse_json_result :
if parse_json_result :
result = { }
result = { }
if content :
if content :
@ -668,10 +691,19 @@ class ACMEAccount(object):
'''
'''
if self . uri is None :
if self . uri is None :
raise ModuleFailException ( " Account URI unknown " )
raise ModuleFailException ( " Account URI unknown " )
data = { }
if self . version == 1 :
if self . version == 1 :
data = { }
data [ ' resource ' ] = ' reg '
data [ ' resource ' ] = ' reg '
result , info = self . send_signed_request ( self . uri , data )
result , info = self . send_signed_request ( self . uri , data )
else :
# try POST-as-GET first (draft-15 or newer)
data = None
result , info = self . send_signed_request ( self . uri , data )
# check whether that failed with a malformed request error
if info [ ' status ' ] > = 400 and result . get ( ' type ' ) == ' urn:ietf:params:acme:error:malformed ' :
# retry as a regular POST (with no changed data) for pre-draft-15 ACME servers
data = { }
result , info = self . send_signed_request ( self . uri , data )
if info [ ' status ' ] in ( 400 , 403 ) and result . get ( ' type ' ) == ' urn:ietf:params:acme:error:unauthorized ' :
if info [ ' status ' ] in ( 400 , 403 ) and result . get ( ' type ' ) == ' urn:ietf:params:acme:error:unauthorized ' :
# Returned when account is deactivated
# Returned when account is deactivated
return None
return None