Class AcmeClientSpi
- java.lang.Object
-
- org.wildfly.security.x500.cert.acme.AcmeClientSpi
-
public abstract class AcmeClientSpi extends Object
SPI for an Automatic Certificate Management Environment (ACME) client provider to implement.- Since:
- 1.5.0
- Author:
- Farah Juma
-
-
Field Summary
Fields Modifier and Type Field Description private static StringCHARSETprivate static int[]CONTENT_TYPE_DELIMSstatic intDEFAULT_EC_KEY_SIZEThe default key size that will be used if the key algorithm name is EC.static StringDEFAULT_KEY_ALGORITHM_NAMEThe default key algorithm name.static intDEFAULT_KEY_SIZEThe default key size that will be used if the key algorithm name is not EC.private static longDEFAULT_RETRY_AFTER_MILLIprivate static jakarta.json.JsonObjectEMPTY_PAYLOADprivate static StringEMPTY_STRINGprivate static intMAX_RETRIESprivate static StringUSER_AGENT_STRINGprivate static StringUTF_8
-
Constructor Summary
Constructors Constructor Description AcmeClientSpi()
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Concrete Methods Modifier and Type Method Description voidchangeAccountKey(AcmeAccount account, boolean staging)Change the key that is associated with the given ACME account.voidchangeAccountKey(AcmeAccount account, boolean staging, X509Certificate certificate, PrivateKey privateKey)Change the key that is associated with the given ACME account.private static booleancheckContentType(HttpURLConnection connection, String expectedMediaType)abstract voidcleanupAfterChallenge(AcmeAccount account, AcmeChallenge challenge)Undo the actions that were taken to prove control of the identifier associated with the given challenge.booleancreateAccount(AcmeAccount account, boolean staging)Create an account with an ACME server using the given account information.booleancreateAccount(AcmeAccount account, boolean staging, boolean onlyReturnExisting)Create an account with an ACME server using the given account information.StringcreateAuthorization(AcmeAccount account, boolean staging, String domainName)Create an authorization for the given identifier.voiddeactivateAccount(AcmeAccount account, boolean staging)Deactivate the given ACME account.voiddeactivateAuthorization(AcmeAccount account, boolean staging, String authorizationUrl)Deactivate an authorization.private StringgetAccountUrl(AcmeAccount account, boolean staging)private static InputStreamgetConvertedInputStream(InputStream inputStream)private static LinkedHashSet<String>getDomainNames(String[] domainNames)private static intgetECSignatureByteLength(String signatureAlgorithm)private static StringgetEncodedJson(jakarta.json.JsonObject jsonObject)private StringgetEncodedProtectedHeader(boolean useJwk, String resourceUrl, AcmeAccount account, boolean staging)private static StringgetEncodedProtectedHeader(String algHeader, PublicKey publicKey, String resourceUrl)private static StringgetEncodedSignature(PrivateKey privateKey, String signatureAlgorithm, String encodedProtectedHeader, String encodedPayload)private static StringgetEncodedSignature(PrivateKey privateKey, Signature signature, String encodedProtectedHeader, String encodedPayload)private static jakarta.json.JsonObjectgetJsonResponse(HttpURLConnection connection)private static jakarta.json.JsonObjectgetJws(String encodedProtectedHeader, String encodedPayload, String encodedSignature)private static StringgetLocation(HttpURLConnection connection, String urlType)AcmeMetadatagetMetadata(AcmeAccount account, boolean staging)Get the metadata associated with the ACME server.byte[]getNewNonce(AcmeAccount account, boolean staging)Get a new nonce for the given account from the ACME server.private byte[]getNonce(AcmeAccount account, boolean staging)private static StringgetOptionalJsonString(jakarta.json.JsonObject jsonObject, String name)private static X509Certificate[]getPemCertificateChain(HttpURLConnection connection)private static StringgetProblemMessage(jakarta.json.JsonObject jsonResponse)private static StringgetProblemMessages(jakarta.json.JsonObject errorResponse)private static byte[]getReplayNonce(HttpURLConnection connection)private URLgetResourceUrl(AcmeAccount account, AcmeResource resource, boolean staging)Map<AcmeResource,URL>getResourceUrls(AcmeAccount account, boolean staging)Get the resource URLs needed to perform operations from the ACME server.private static longgetRetryAfter(HttpURLConnection connection, boolean useDefaultIfHeaderNotPresent)private static StringgetSanitizedDomainName(String domainName)private static voidhandleAcmeErrorResponse(HttpURLConnection connection, int responseCode)private static booleanisDelim(int c, int... delims)X509CertificateChainAndSigningKeyobtainCertificateChain(AcmeAccount account, boolean staging, String... domainNames)Obtain a certificate chain using the given ACME account.X509CertificateChainAndSigningKeyobtainCertificateChain(AcmeAccount account, boolean staging, String keyAlgorithmName, int keySize, String... domainNames)Obtain a certificate chain using the given ACME account.private jakarta.json.JsonObjectpollResourceUntilFinalized(AcmeAccount account, boolean staging, String resourceUrl)abstract AcmeChallengeproveIdentifierControl(AcmeAccount account, List<AcmeChallenge> challenges)Prove control of the identifier associated with the given list of challenges.(package private) String[]queryAccountContactUrls(AcmeAccount account, boolean staging)(package private) StringqueryAccountStatus(AcmeAccount account, boolean staging)private AcmeChallengerespondToChallenges(AcmeAccount account, boolean staging, jakarta.json.JsonObject authorization)voidrevokeCertificate(AcmeAccount account, boolean staging, X509Certificate certificate)Revoke the given certificate.voidrevokeCertificate(AcmeAccount account, boolean staging, X509Certificate certificate, CRLReason reason)Revoke the given certificate.private HttpURLConnectionsendGetRequest(String resourceUrl, int expectedResponseCode, String expectedContentType)private HttpURLConnectionsendPostAsGetRequest(AcmeAccount account, boolean staging, String resourceUrl, String expectedContentType, int... expectedResponseCodes)private HttpURLConnectionsendPostRequestWithRetries(AcmeAccount account, boolean staging, String resourceUrl, boolean useJwk, String encodedPayload, int... expectedResponseCodes)private HttpURLConnectionsendPostRequestWithRetries(AcmeAccount account, boolean staging, String resourceUrl, boolean useJwk, String encodedPayload, String expectedContentType, int... expectedResponseCodes)private static voidskipDelims(org.wildfly.common.iteration.CodePointIterator di, org.wildfly.common.iteration.CodePointIterator cpi, int... delims)voidupdateAccount(AcmeAccount account, boolean staging, boolean termsOfServiceAgreed)Update whether or not the terms of service have been agreed to for an account with an ACME server.voidupdateAccount(AcmeAccount account, boolean staging, boolean termsOfServiceAgreed, String[] contactUrls)Update an account with an ACME server using the given account information.voidupdateAccount(AcmeAccount account, boolean staging, String[] contactUrls)Update the contact URLs for an account with an ACME server.
-
-
-
Field Detail
-
DEFAULT_EC_KEY_SIZE
public static final int DEFAULT_EC_KEY_SIZE
The default key size that will be used if the key algorithm name is EC.- See Also:
- Constant Field Values
-
DEFAULT_KEY_SIZE
public static final int DEFAULT_KEY_SIZE
The default key size that will be used if the key algorithm name is not EC.- See Also:
- Constant Field Values
-
DEFAULT_KEY_ALGORITHM_NAME
public static final String DEFAULT_KEY_ALGORITHM_NAME
The default key algorithm name.- See Also:
- Constant Field Values
-
MAX_RETRIES
private static final int MAX_RETRIES
- See Also:
- Constant Field Values
-
DEFAULT_RETRY_AFTER_MILLI
private static final long DEFAULT_RETRY_AFTER_MILLI
- See Also:
- Constant Field Values
-
CONTENT_TYPE_DELIMS
private static final int[] CONTENT_TYPE_DELIMS
-
CHARSET
private static final String CHARSET
- See Also:
- Constant Field Values
-
UTF_8
private static final String UTF_8
- See Also:
- Constant Field Values
-
USER_AGENT_STRING
private static final String USER_AGENT_STRING
-
EMPTY_PAYLOAD
private static final jakarta.json.JsonObject EMPTY_PAYLOAD
-
EMPTY_STRING
private static final String EMPTY_STRING
- See Also:
- Constant Field Values
-
-
Method Detail
-
getResourceUrls
public Map<AcmeResource,URL> getResourceUrls(AcmeAccount account, boolean staging) throws AcmeException
Get the resource URLs needed to perform operations from the ACME server.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be used- Returns:
- a map of ACME resources to URLs
- Throws:
AcmeException- if an error occurs while attempting to get the resource URLs from the ACME server
-
getMetadata
public AcmeMetadata getMetadata(AcmeAccount account, boolean staging) throws AcmeException
Get the metadata associated with the ACME server.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be used- Returns:
- the metadata associated with the ACME server (may be
null) - Throws:
AcmeException- if an error occurs while attempting to get the metadata associated with the ACME server
-
createAccount
public boolean createAccount(AcmeAccount account, boolean staging) throws AcmeException
Create an account with an ACME server using the given account information.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be used- Returns:
trueif the account was created,falseif the account already existed- Throws:
AcmeException- if an error occurs while attempting to create or lookup an account with the ACME server
-
createAccount
public boolean createAccount(AcmeAccount account, boolean staging, boolean onlyReturnExisting) throws AcmeException
Create an account with an ACME server using the given account information.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedonlyReturnExisting-trueif the ACME server should not create a new account if one does not already exist (this allows an existing account's URL to be looked up and populated using the account key)- Returns:
trueif the account was created,falseif the account already existed- Throws:
AcmeException- if an error occurs while attempting to create or lookup an account with the ACME server or ifonlyReturnExistingis set totrueand the account does not exist
-
updateAccount
public void updateAccount(AcmeAccount account, boolean staging, boolean termsOfServiceAgreed) throws AcmeException
Update whether or not the terms of service have been agreed to for an account with an ACME server.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedtermsOfServiceAgreed- the new value for whether or not the terms of service have been agreed to- Throws:
AcmeException- if an error occurs while attempting to update the account
-
updateAccount
public void updateAccount(AcmeAccount account, boolean staging, String[] contactUrls) throws AcmeException
Update the contact URLs for an account with an ACME server.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedcontactUrls- the new account contact URLs- Throws:
AcmeException- if an error occurs while attempting to update the account
-
updateAccount
public void updateAccount(AcmeAccount account, boolean staging, boolean termsOfServiceAgreed, String[] contactUrls) throws AcmeException
Update an account with an ACME server using the given account information.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedtermsOfServiceAgreed- the new value for whether or not the terms of service have been agreed tocontactUrls- the new account contact URLs- Throws:
AcmeException- if an error occurs while attempting to update the account
-
changeAccountKey
public void changeAccountKey(AcmeAccount account, boolean staging) throws AcmeException
Change the key that is associated with the given ACME account.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be used- Throws:
AcmeException- if an error occurs while attempting to change the key that is associated with the given ACME account
-
changeAccountKey
public void changeAccountKey(AcmeAccount account, boolean staging, X509Certificate certificate, PrivateKey privateKey) throws AcmeException
Change the key that is associated with the given ACME account.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedcertificate- the new certificate to associate with the given ACME account (must not benull)privateKey- the new private key to associate with the given ACME account (must not benull)- Throws:
AcmeException- if an error occurs while attempting to change the key that is associated with the given ACME account
-
deactivateAccount
public void deactivateAccount(AcmeAccount account, boolean staging) throws AcmeException
Deactivate the given ACME account. It is not possible to reactivate an ACME account after it has been deactivated.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be used- Throws:
AcmeException- if an error occurs while attempting to deactivate the given ACME account
-
obtainCertificateChain
public X509CertificateChainAndSigningKey obtainCertificateChain(AcmeAccount account, boolean staging, String... domainNames) throws AcmeException
Obtain a certificate chain using the given ACME account.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be useddomainNames- the domain names to request the certificate for (must not benull)- Returns:
- the X509 certificate chain and private key
- Throws:
AcmeException- if an occur occurs while attempting to obtain the certificate
-
obtainCertificateChain
public X509CertificateChainAndSigningKey obtainCertificateChain(AcmeAccount account, boolean staging, String keyAlgorithmName, int keySize, String... domainNames) throws AcmeException
Obtain a certificate chain using the given ACME account.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedkeyAlgorithmName- the optional key algorithm name to use when generating the key pair (may benull)keySize- the optional key size to use when generating the key pair (-1 to indicate that the default key size should be used)domainNames- the domain names to request the certificate for (must not benull)- Returns:
- the X509 certificate chain and private key
- Throws:
AcmeException- if an occur occurs while attempting to obtain the certificate
-
createAuthorization
public String createAuthorization(AcmeAccount account, boolean staging, String domainName) throws AcmeException
Create an authorization for the given identifier.This method allows an ACME client to obtain authorization for an identifier proactively before attempting to obtain a certificate.
- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be useddomainName- the domain name to create an authorization for (must not benull)- Returns:
- the authorization URL corresponding to the given identifier
- Throws:
AcmeException- if an error occurs while attempting to create an authorization for the given identifier
-
deactivateAuthorization
public void deactivateAuthorization(AcmeAccount account, boolean staging, String authorizationUrl) throws AcmeException
Deactivate an authorization.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedauthorizationUrl- the authorization url (must not benull)- Throws:
AcmeException- if an error occurs while attempting to deactivate an authorization for the given identifier
-
proveIdentifierControl
public abstract AcmeChallenge proveIdentifierControl(AcmeAccount account, List<AcmeChallenge> challenges) throws AcmeException
Prove control of the identifier associated with the given list of challenges.This method should select one challenge from the given list of challenges from the ACME server to prove control of the identifier associated with the challenges as specified by the ACME v2 protocol.
- Parameters:
account- the ACME account information to use (must not benull)challenges- the list of challenges from the ACME server (must not benull)- Returns:
- the challenge that was selected and used to prove control of the identifier
- Throws:
AcmeException- if an error occurs while attempting to provide control of the identifier associated with the challenges or if none of the challenge types are supported by this client
-
cleanupAfterChallenge
public abstract void cleanupAfterChallenge(AcmeAccount account, AcmeChallenge challenge) throws AcmeException
Undo the actions that were taken to prove control of the identifier associated with the given challenge.- Parameters:
account- the ACME account information to use (must not benull)challenge- the challenge (must not benull)- Throws:
AcmeException- if an error occurs while attempting to undo the actions that were taken to prove control of the identifier associated with the given challenge
-
revokeCertificate
public void revokeCertificate(AcmeAccount account, boolean staging, X509Certificate certificate) throws AcmeException
Revoke the given certificate.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedcertificate- the certificate to be revoked (must not benull)- Throws:
AcmeException- if an error occurs while attempting to revoke the given certificate
-
revokeCertificate
public void revokeCertificate(AcmeAccount account, boolean staging, X509Certificate certificate, CRLReason reason) throws AcmeException
Revoke the given certificate.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be usedcertificate- the certificate to be revoked (must not benull)reason- the optional reason why the certificate is being revoked (may benull)- Throws:
AcmeException- if an error occurs while attempting to revoke the given certificate
-
getNewNonce
public byte[] getNewNonce(AcmeAccount account, boolean staging) throws AcmeException
Get a new nonce for the given account from the ACME server.- Parameters:
account- the ACME account information to use (must not benull)staging- whether or not the staging server URL should be used- Returns:
- nonce the new nonce for the given account
- Throws:
AcmeException- if an error occurs while attempting to get the new nonce from the ACME server
-
queryAccountContactUrls
String[] queryAccountContactUrls(AcmeAccount account, boolean staging) throws AcmeException
- Throws:
AcmeException
-
queryAccountStatus
String queryAccountStatus(AcmeAccount account, boolean staging) throws AcmeException
- Throws:
AcmeException
-
getResourceUrl
private URL getResourceUrl(AcmeAccount account, AcmeResource resource, boolean staging) throws AcmeException
- Throws:
AcmeException
-
sendGetRequest
private HttpURLConnection sendGetRequest(String resourceUrl, int expectedResponseCode, String expectedContentType) throws AcmeException
- Throws:
AcmeException
-
sendPostAsGetRequest
private HttpURLConnection sendPostAsGetRequest(AcmeAccount account, boolean staging, String resourceUrl, String expectedContentType, int... expectedResponseCodes) throws AcmeException
- Throws:
AcmeException
-
sendPostRequestWithRetries
private HttpURLConnection sendPostRequestWithRetries(AcmeAccount account, boolean staging, String resourceUrl, boolean useJwk, String encodedPayload, int... expectedResponseCodes) throws AcmeException
- Throws:
AcmeException
-
sendPostRequestWithRetries
private HttpURLConnection sendPostRequestWithRetries(AcmeAccount account, boolean staging, String resourceUrl, boolean useJwk, String encodedPayload, String expectedContentType, int... expectedResponseCodes) throws AcmeException
- Throws:
AcmeException
-
pollResourceUntilFinalized
private jakarta.json.JsonObject pollResourceUntilFinalized(AcmeAccount account, boolean staging, String resourceUrl) throws AcmeException
- Throws:
AcmeException
-
respondToChallenges
private AcmeChallenge respondToChallenges(AcmeAccount account, boolean staging, jakarta.json.JsonObject authorization) throws AcmeException
- Throws:
AcmeException
-
getDomainNames
private static LinkedHashSet<String> getDomainNames(String[] domainNames) throws AcmeException
- Throws:
AcmeException
-
getSanitizedDomainName
private static String getSanitizedDomainName(String domainName) throws AcmeException
- Throws:
AcmeException
-
getJsonResponse
private static jakarta.json.JsonObject getJsonResponse(HttpURLConnection connection) throws AcmeException
- Throws:
AcmeException
-
getReplayNonce
private static byte[] getReplayNonce(HttpURLConnection connection) throws AcmeException
- Throws:
AcmeException
-
getLocation
private static String getLocation(HttpURLConnection connection, String urlType) throws AcmeException
- Throws:
AcmeException
-
getRetryAfter
private static long getRetryAfter(HttpURLConnection connection, boolean useDefaultIfHeaderNotPresent) throws AcmeException
- Throws:
AcmeException
-
handleAcmeErrorResponse
private static void handleAcmeErrorResponse(HttpURLConnection connection, int responseCode) throws AcmeException
- Throws:
AcmeException
-
getProblemMessages
private static String getProblemMessages(jakarta.json.JsonObject errorResponse)
-
getProblemMessage
private static String getProblemMessage(jakarta.json.JsonObject jsonResponse)
-
getOptionalJsonString
private static String getOptionalJsonString(jakarta.json.JsonObject jsonObject, String name)
-
getPemCertificateChain
private static X509Certificate[] getPemCertificateChain(HttpURLConnection connection) throws AcmeException
- Throws:
AcmeException
-
getEncodedJson
private static String getEncodedJson(jakarta.json.JsonObject jsonObject)
-
getJws
private static jakarta.json.JsonObject getJws(String encodedProtectedHeader, String encodedPayload, String encodedSignature)
-
getEncodedProtectedHeader
private static String getEncodedProtectedHeader(String algHeader, PublicKey publicKey, String resourceUrl)
-
getEncodedProtectedHeader
private String getEncodedProtectedHeader(boolean useJwk, String resourceUrl, AcmeAccount account, boolean staging) throws AcmeException
- Throws:
AcmeException
-
getEncodedSignature
private static String getEncodedSignature(PrivateKey privateKey, Signature signature, String encodedProtectedHeader, String encodedPayload) throws AcmeException
- Throws:
AcmeException
-
getEncodedSignature
private static String getEncodedSignature(PrivateKey privateKey, String signatureAlgorithm, String encodedProtectedHeader, String encodedPayload) throws AcmeException
- Throws:
AcmeException
-
getECSignatureByteLength
private static int getECSignatureByteLength(String signatureAlgorithm) throws AcmeException
- Throws:
AcmeException
-
getNonce
private byte[] getNonce(AcmeAccount account, boolean staging) throws AcmeException
- Throws:
AcmeException
-
getAccountUrl
private String getAccountUrl(AcmeAccount account, boolean staging) throws AcmeException
- Throws:
AcmeException
-
checkContentType
private static boolean checkContentType(HttpURLConnection connection, String expectedMediaType) throws AcmeException
- Throws:
AcmeException
-
skipDelims
private static void skipDelims(org.wildfly.common.iteration.CodePointIterator di, org.wildfly.common.iteration.CodePointIterator cpi, int... delims) throws AcmeException- Throws:
AcmeException
-
isDelim
private static boolean isDelim(int c, int... delims)
-
getConvertedInputStream
private static InputStream getConvertedInputStream(InputStream inputStream) throws IOException
- Throws:
IOException
-
-